├── update-blocklist.sh ├── onion2web-dev-1.rockspec ├── install.sh ├── LICENSE ├── README.md ├── example.nginx └── onion2web.lua /update-blocklist.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -xue 4 | 5 | curl https://ahmia.fi/blacklist/banned/ | egrep -o '[0-9a-f]{32}' > /etc/blocklist-ahmia.txt 6 | cat /etc/blocklist-*.txt > /etc/blocklist.txt 7 | 8 | service nginx reload 9 | -------------------------------------------------------------------------------- /onion2web-dev-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "onion2web" 2 | version = "dev-1" 3 | source = { 4 | url = 'git://github.com/starius/onion2web', 5 | tag = 'master', 6 | } 7 | description = { 8 | summary = "Access .onion sites without Tor Browser", 9 | homepage = "https://github.com/starius/onion2web", 10 | maintainer = "Boris Nagaev ", 11 | license = "MIT" 12 | } 13 | dependencies = { 14 | "lua ~> 5.1", 15 | "socks5 >= 1.7" 16 | } 17 | build = { 18 | type = "builtin", 19 | modules = { 20 | onion2web = "onion2web.lua", 21 | }, 22 | } 23 | 24 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -xue 4 | 5 | apt-get --yes install nginx-extras 6 | apt-get --yes install luarocks 7 | apt-get --yes install curl 8 | luarocks install onion2web 9 | 10 | cp example.nginx /etc/nginx/nginx.conf 11 | 12 | wget -r -k -p -np -e robots=off -E https://starius.github.io/onion2web/ 13 | mkdir -p /var/www 14 | rm -rf /var/www/onion2web 15 | cp -r starius.github.io/onion2web /var/www/onion2web 16 | 17 | wget https://raw.githubusercontent.com/starius/config/master/.bin/install-tor2web 18 | chmod +x install-tor2web 19 | ./install-tor2web 20 | 21 | service nginx restart 22 | 23 | curl "https://raw.githubusercontent.com/globaleaks/Tor2web/b6ead9ffeaa0d52cc70b4bc9d82a9bbea45b94e0/lists/blocklist_hashed.txt" > /etc/blocklist-tor2web.txt 24 | cp update-blocklist.sh /etc/cron.daily/update-blocklist.sh 25 | chmod +x /etc/cron.daily/update-blocklist.sh 26 | /etc/cron.daily/update-blocklist.sh 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Boris Nagaev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | onion2web 2 | ========= 3 | 4 | Access .onion sites without Tor Browser 5 | 6 | [Homepage](http://onion.gq/). 7 | 8 | Dependency: 9 | [lua-resty-socks5](https://github.com/starius/lua-resty-socks5). 10 | 11 | [Paper](http://habrahabr.ru/post/243055/) (in Russian). 12 | 13 | Installation 14 | ------------ 15 | 16 | ```bash 17 | $ sudo luarocks install onion2web 18 | ``` 19 | 20 | Reference 21 | --------- 22 | 23 | This module contains the following functions: 24 | 25 | * `onion2web.handle_onion2web(onion_replacement, 26 | torhost='127.0.0.1', torport=9050, confirmation=true)` - 27 | accept request to onion2web site. 28 | `onion_replacement` is part of gateway domain name, 29 | which replaces `.onion` (e.g., `.onion.gq`). 30 | `torhost` and `torport` are Tor address and SocksPort. 31 | If `confirmation` is true (the default), then 32 | the confirmation page is shown instead of contents 33 | of a hidden service until a user accepts the terms. 34 | 35 | How to use this module to forward requests from 36 | `xxx.onion.gq` to `xxx.onion`: 37 | 38 | ```nginx 39 | server { 40 | listen 80; 41 | server_name *.onion.gq; 42 | location / { 43 | default_type text/html; 44 | content_by_lua ' 45 | require("onion2web").handle_onion2web(".onion.gq"); 46 | '; 47 | } 48 | } 49 | ``` 50 | 51 | To blacklist some .onion sites: 52 | 53 | ```nginx 54 | server { 55 | listen 80; 56 | server_name 57 | .badonion12345678.onion.gq 58 | .anotherbadonion1.onion.gq 59 | ; 60 | return 403; 61 | } 62 | ``` 63 | -------------------------------------------------------------------------------- /example.nginx: -------------------------------------------------------------------------------- 1 | user www-data; 2 | worker_processes 4; 3 | pid /run/nginx.pid; 4 | 5 | events { 6 | worker_connections 100000; 7 | } 8 | 9 | worker_rlimit_nofile 200000; # 2 * worker_connections 10 | 11 | http { 12 | 13 | sendfile on; 14 | tcp_nopush on; 15 | tcp_nodelay on; 16 | keepalive_timeout 65; 17 | types_hash_max_size 2048; 18 | 19 | error_log /dev/null; 20 | access_log /dev/null; 21 | 22 | include /etc/nginx/mime.types; 23 | default_type application/octet-stream; 24 | 25 | server { 26 | listen 80 so_keepalive=10s:10s:8; 27 | server_name onion.gq www.onion.gq; 28 | location / { 29 | default_type text/html; 30 | root /var/www/onion2web/; 31 | } 32 | } 33 | 34 | # For monitoring 35 | # www.pastagdsp33j7aoq.onion.gq without confirmation 36 | server { 37 | listen 80; 38 | server_name www.pastagdsp33j7aoq.onion.gq; 39 | lua_check_client_abort on; 40 | location / { 41 | default_type text/html; 42 | content_by_lua ' 43 | require("onion2web").handle_onion2web( 44 | ".onion.gq", nil, nil, false 45 | ); 46 | '; 47 | } 48 | } 49 | 50 | server { 51 | listen 80; 52 | server_name *.onion.gq; 53 | lua_check_client_abort on; 54 | location / { 55 | default_type text/html; 56 | content_by_lua ' 57 | if not blocklist then 58 | blocklist = {} 59 | local f = io.open("/etc/blocklist.txt") 60 | if f then 61 | for host_md5 in f:lines() do 62 | blocklist[host_md5] = true 63 | end 64 | f:close() 65 | end 66 | end 67 | require("onion2web").handle_onion2web(".onion.gq", 68 | nil, nil, true, blocklist); 69 | '; 70 | } 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /onion2web.lua: -------------------------------------------------------------------------------- 1 | local socks5 = require 'socks5' 2 | local ngx = require 'ngx' 3 | 4 | local onion2web = {} 5 | 6 | local hidden_base = "(" .. string.rep("%w", 16) .. ")" 7 | local hidden_onion = hidden_base .. '%.onion' 8 | 9 | local show_confirmation_form = function() 10 | local host = ngx.req.get_headers()['Host'] 11 | local onion = host:match(hidden_base) .. '.onion' 12 | if ngx.req.get_method() == 'POST' and 13 | ngx.var.uri:match('^/confirm') then 14 | ngx.header['Set-Cookie'] = 'onion2web_confirmed=true;' 15 | return ngx.redirect("/") 16 | end 17 | ngx.say(([[ 18 | 19 | Onion2web 20 | 21 | 22 |

Onion2web

23 | 24 |

25 | 26 | %s does not host this content; 27 | the service is simply a proxy connecting Internet users 28 | to content hosted inside the 30 | Tor network. 31 | Please be aware that when you access this site through a 32 | Onion2web proxy you are not anonymous. 33 | To obtain anonymity, you are strongly advised to 35 | download the Tor Browser Bundle 36 | and access this content over Tor. 37 |
38 | By accessing this site you acknowledge 39 | that you have understood: 40 | 48 |
49 | 50 |
By the way, just to be clear:
51 |

52 |
THIS SERVER IS A PROXY AND IT'S NOT 53 | HOSTING THE TOR HIDDEN SERVICE SITE %s 54 |

55 |
56 | 58 |
59 |
60 | 61 | Report the site 62 | 63 | 64 | Fork me on GitHub 68 | 69 | 70 | 71 | ]]):format(host, onion, onion)) 72 | end 73 | 74 | onion2web.handle_onion2web = function(onion_replacement, 75 | torhost, torport, confirmation, blocklist) 76 | if not torhost then 77 | torhost = '127.0.0.1' 78 | end 79 | if not torport then 80 | torport = 9050 81 | end 82 | if confirmation == nil then 83 | confirmation = true 84 | end 85 | local host = ngx.req.get_headers()['Host'] 86 | -- Check against the blocklist. 87 | local onion = host:match(hidden_base) .. '.onion' 88 | local digest = ngx.md5(onion) 89 | if blocklist and blocklist[digest] then 90 | ngx.say('Domain ' .. host .. ' is blocked ' .. 91 | 'in the name of good and justice') 92 | return 93 | end 94 | local repl = hidden_base .. onion_replacement 95 | if not host:match('^' .. repl .. '$') and 96 | not host:match('%.' .. repl .. '$') then 97 | ngx.say('Bad domain: ' .. host) 98 | return 99 | end 100 | local cookies = ngx.req.get_headers()['Cookie'] 101 | if confirmation and 102 | (not cookies or 103 | not cookies:match('onion2web_confirmed=true')) then 104 | show_confirmation_form() 105 | return 106 | end 107 | local change_only_html = true 108 | socks5.handle_request(torhost, torport, 109 | function(clheader) 110 | return clheader 111 | :gsub("HTTP/1.1(%c+)", "HTTP/1.0%1") 112 | :gsub(repl, "%1.onion") 113 | :gsub("Connection: keep%-alive", "Connection: close") 114 | :gsub("Accept%-Encoding: [%w%p ]+%c+", "") 115 | end, 116 | function(soheader) 117 | return soheader 118 | :gsub(hidden_onion, "%1" .. onion_replacement) 119 | end, 120 | change_only_html 121 | ) 122 | end 123 | 124 | return onion2web 125 | 126 | --------------------------------------------------------------------------------