- PVSM.RU - https://www.pvsm.ru -

Обходим блокировку сайта фильтрующим прокси при помощи скрипта во имя Луны

Блокировки продолжаются а я всё также не приветствую отдачу не шифрованного HTTP трафика в заморские прокси [1], Tor [2], анонимайзеры [3] и включение экономии трафика [4] в браузере. Пока есть возможность я буду пытаться ходить на сайты прямо. Заодно скорость связи с сайтом не будет зависеть от загруженности стороннего сервиса.

Я поставил на Firefox плагин RequestPolicy [5] и обнаружил в HTTP хедерах на заблокированном сайте.

X-Squid-Error:"403 Access Denied"

Это значит что соединение к сайту проходит через прозрачный прокси провайдера который блокирует доступ к сайту из реестра [6].

В этой статье я попробую обойти это ограничение при помощи локального прокси написанного на Lua (Вики [7])

Скачав LuaSocket 2.0.2 [8] я написал небольшой скрипт локального прокси.

require "socket"

local cors = {}
function main()
	local proxy_bind = socket.tcp()
	proxy_bind:setoption("reuseaddr", true) -- На всякий случай
	proxy_bind:bind("localhost", 8080) -- Принимаем подключения только от локального клиента
	proxy_bind:listen(100) -- 100 подключений в очереди
	proxy_bind:settimeout(0) -- 0s Позволяет не задерживаться ожидая данных и забрать из буфера сразу всё.
	repeat -- Главный цикл который принимает подключения
		local client, accept_err = proxy_bind:accept()
		if (client) then
			local new_cor = coroutine.create(new_client)
			local ok, err = coroutine.resume(new_cor, client)
			if (ok) then
				table.insert(cors, new_cor)
			end
		end
		local new_list = {}
		for id, cor in ipairs(cors) do
			local ok, err = coroutine.resume(cor)
			if (ok) then
				table.insert(new_list, cor)
			end
		end
		cors = new_list
		socket.sleep(0.001) -- Чтоб не сильно нагружать процессор
	until accept_err and (accept_err ~= "timeout")
end

-- Читаем хедеры и соединяемся с конечным сайтом сквозь фильтрующий прокси
function new_client(client)
	client:settimeout(0)
	local headers, err = get_data(client:receive("*a"))
	local host, port = get_host_port(headers)
	local server = socket.connect(host, port)
	print("NC", host, port)
	if (server) then
		if (not send_connect(server, string.format("%s:%s", socket.dns.toip(host), port))) then
			server:close()
			server = socket.connect(host, port)
		end
		if (server) then
			server:send(headers)
			cycle_data(server, client, host)
		end
	end
	print("CLOSED", host, port)
	server:close()
	client:close()
end

function get_data(data, err, part, marker)
	data = (data or part)
	return data, err
end

function get_host_port(headers)
	if headers and (#headers > 0) then
		if not (headers:find(" HTTP/1.11310Host: ", 1, true)) then
			return
		end
		local _, _, host, port = headers:find(" HTTP/1.11310Host: ([a-z0-9%.%-]+):?([0-9]*)1310")
		if (#port > 0) then
			port = tonumber(port)
		else
			port = 80
		end
		return host, port
	end
end

-- Используем метод CONNECT который превращает фильтрующий прокси в TCP трубу
local connect = "CONNECT %s HTTP/1.11310Host: %s13101310"
function send_connect(server, address)
	server:send(string.format(connect, address, address))
	server:settimeout(0.1)
	local headers, err = get_data(server:receive("*a"))
	return headers:find("^HTTP/1.[01] 200")
end

-- Пересылаем данные в обе стороны

function cycle_data(server, client, host, port)
	local _in_, out = server, client
	repeat
		_in_:settimeout(0)
		out:settimeout(1)
		
		local data, receive_err = get_data(_in_:receive("*a"))
		
		if data and (#data > 0) then
			data = data:gsub("1310Connection%: keep%-alive1310", "1310Connection: close1310")
			local index, send_err = send_data(out, data)
		end
		
		coroutine.yield() -- Даём скрипту обработать другие подключения
		
	until (receive_err and (receive_err ~= "timeout")) or (send_err and (send_err ~= "timeout"))
end

function send_data(out, data)
	local index = 0
	repeat
		index = index +1
		index, err = get_index(out:send(data, index))
	until index >= #data or (err and (err ~= "timeout"))
	
	return index, err
end

function get_index(index, err, partial_index)
	return (index or partial_index), err
end

main()

Сохраняем скрипт как «proxy.lua» в распакованную папку с LuaSocket 2.0.2.

Создаём простой «proxy.bat» файл для запуска «proxy.lua», который сохраним там же.

%~d0
cd %~p0
lua5.1 proxy.lua
pause

Теперь подредактируем «proxy.pac» из прошлой статьи [9]. (Адреса изменены)

function FindProxyForURL(url, host) {

  if (shExpMatch(url, "http://*") && shExpMatch(host, "rutracker.og")) {
    return "PROXY localhost:8080; PROXY rutracker.og; DIRECT";
  }

  /* 
  Для HTTPS соединений через HTTP прокси метод CONNECT используется автоматически
  */

  if (shExpMatch(url, "https://*") && shExpMatch(host, "rutracker.og")) {
    return "PROXY rutracker.og; DIRECT";
  }

  return "DIRECT";
}

Запускаем прокси двойным кликом по «proxy.bat». Перезапускаем браузер и открываем rutracker.og.

Скрипт писался быстро и чинился костылями. Это не полноценный прокси.
Если кто придумает решение проще я буду очень рад.

Дополнительно:
На случай возможного разделегирования домена в файл hosts [10] добавим строку (Адреса изменены):

#198.51.100.0       rutracker.og

И если домен разделегируют можно раскоментировать строчку удалив "#" и вернуть доступ к серверу.

198.51.100.0       rutracker.og

Так например можно вернуть доступ к серверу rutor.og (адрес изменён) взяв его ip из реестра [11] или других источников.

Использована информация:
Lua 5.1 Reference Manual [12]
LuaSocket: TCP/IP support [13]
Обходим блокировку сайта DPI двумя скриптами [9]
Proxy Auto Configuration (PAC) [14]
hosts — Википедия [15]

Автор: ivan386

Источник [16]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/proxy/111399

Ссылки в тексте:

[1] прокси: https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%BE%D0%BA%D1%81%D0%B8-%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80

[2] Tor: https://ru.wikipedia.org/wiki/Tor

[3] анонимайзеры: https://ru.wikipedia.org/wiki/%D0%90%D0%BD%D0%BE%D0%BD%D0%B8%D0%BC%D0%B0%D0%B9%D0%B7%D0%B5%D1%80

[4] экономии трафика: https://support.google.com/chrome/answer/2392284?hl=ru

[5] RequestPolicy: https://addons.mozilla.org/Ru/firefox/addon/requestpolicy/

[6] реестра: https://ru.wikipedia.org/wiki/%D0%95%D0%B4%D0%B8%D0%BD%D1%8B%D0%B9_%D1%80%D0%B5%D0%B5%D1%81%D1%82%D1%80_%D0%B7%D0%B0%D0%BF%D1%80%D0%B5%D1%89%D1%91%D0%BD%D0%BD%D1%8B%D1%85_%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2

[7] Вики: https://ru.wikipedia.org/wiki/Lua

[8] LuaSocket 2.0.2: http://files.luaforge.net/releases/luasocket/luasocket/luasocket-2.0.2

[9] статьи: https://habrahabr.ru/post/276141/

[10] файл hosts: https://ru.wikipedia.org/wiki/Hosts#.D0.A0.D0.B0.D1.81.D0.BF.D0.BE.D0.BB.D0.BE.D0.B6.D0.B5.D0.BD.D0.B8.D0.B5_.D0.B8_.D1.81.D0.BE.D0.B4.D0.B5.D1.80.D0.B6.D0.B0.D0.BD.D0.B8.D0.B5

[11] реестра: https://antizapret.info/

[12] Lua 5.1 Reference Manual: http://www.lua.org/manual/5.1/manual.html

[13] LuaSocket: TCP/IP support: http://w3.impa.br/~diego/software/luasocket/tcp.html

[14] Proxy Auto Configuration (PAC): https://habrahabr.ru/sandbox/19972/

[15] hosts — Википедия: https://ru.wikipedia.org/wiki/Hosts

[16] Источник: https://habrahabr.ru/post/276623/