穿透内网的反弹代理

舍友滚去实习了,恰好又要选课。学校的教务系统似乎无法从外网访问,于是便考虑给他们搞个代理。

一般情况下,代理服务器需要运行在内网,在公网边界暴露访问端口以便外网用户得以访问。但是很显然我没有校网边界路由器的权限,不可能去改防火墙。

好在我有一台VPS,在这种双方用户无法直连的情况下,就只能反过来利用第三台机器做中转了。思路很直接,校网的代理主动连接到中转服务器,再由中转服务器提供代理服务接收请求转发到校网的代理服务器中。

这种做法被叫做“反弹代理”。

搭建sock5反弹代理

在网上搜了一圈,发现有一个软件sscoks能支持反弹代理。遂下载编译。

在VPS上开放了端口8888用于反弹代理连接,并在1080端口提供Sock5代理服务:

./rcsocks -l 1080 -p 8888 -vv

在校网使用树莓派架设一个反弹代理的客户端,启动时自动连接到VPS的8888端口:

./rssocks -vv -s bakachu.cn:8888

这样,反弹代理就搭建完毕了,之后只要用代理客户端连接VPS的1080端口就能获得服务。

转换成HTTP代理

但是Sock5代理的功能太强大,如果只提供HTTP代理服务就要做转换了。这里,我直接使用tengine配合其上的lua模块编写一个小的转换脚本来将HTTP请求转到本地的sock5代理上。

tengine配置:

server {
	listen 8080;
	server_name proxy.bakachu.cn;

	charset utf-8;

	access_log /home/ngx-logs/proxy.access.log;
	error_log /home/ngx-logs/proxy.error.log;

	location / {
		lua_socket_read_timeout 300s;

		default_type text/html;
		content_by_lua_file /data/proxy.lua;
	}
}

lua脚本:

local socks5 = require("resty.socks5")
local base64 = require("base64")

local headers = ngx.req.get_headers()
local proxy_auth = headers["Proxy-Authorization"]
if proxy_auth == nil or proxy_auth == "" then
	ngx.header["Proxy-Authenticate"] = 'Basic realm="Passwd required."'
	ngx.exit(407)
else
	local _, _, base64enc = string.find(proxy_auth, "Basic (.+)")
	local authinfo = base64.decode(base64enc)
	local _, _, username, passwd = string.find(authinfo, "(.+):(.+)")

	if username ~= "proxy_username" or passwd ~= "proxy_passwd" then
		ngx.header["Proxy-Authorization"] = ""
		ngx.header["Proxy-Authenticate"] = 'Basic realm="Bad username or password."'
		ngx.exit(407)
	else
		socks5.handle_request("127.0.0.1", 1080)
	end
end

这样,就可以通过http://proxy.bakachu.cn:8080和用户名密码来访问sock5代理了。

参考