💾 Archived View for gmi.noulin.net › 2022-12-23-using-tor.gmi captured on 2023-09-28 at 18:14:30. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-01-29)
-=-=-=-=-=-=-
date: 2022-12-23 14:19:31
categories: tools
firstPublishDate: 2022-12-23 14:19:31
Tor is network that preserves the anonymity of the users and services.
On the
, you can download the tor browser and browse the web anonymously.
The list of active tor relays is available at
https://nusenu.github.io/OrNetStats/w/
https://nusenu.github.io/OrNetStats/w/
.
In this article, I show how to create onion services in Debian Bullseye:
Onion services are within the tor network and don't need tor exit nodes.
To create onion service, you need:
After starting tor, it takes less than 30 seconds for the onion service to become accessible.
To create a regular internet service, you need:
From my experience, the tor network is quite slow, it's like using the internet with a 56kbauds modem.
The web server I use is my simple web server: liveserver.
First, install `sheepy`(build system) as root:
apt-get install tor build-essential git clone https://spartatek.se/git/sheepy.git cd sheepy ./install.sh
Then, start the web server, it opens port 80:
git clone https://noulin.net/git/liveserver.git cd liveserver ./liveserver.c
Create a tor configuration in your home directory (replace USER with your username):
vi ~/.torrc HiddenServiceDir /home/USER/tor/my_website HiddenServicePort 80 127.0.0.1:8080
The onion service configuration is stored in `/home/USER/tor/my_website`, create these directories with correct permissions and start tor (as username, not as root):
mkdir -p /home/USER/tor/my_website chmod 700 /home/USER/tor/my_website chmod 100 /home/USER/tor # start tor tor -f ~/.torrc
The onion address is generated by tor and stored in `/home/USER/tor/my_website/hostname`
cat /home/USER/tor/my_website/hostname abc...onion
To connect to the server, open `abc...onion` in the tor browser.
It is possible to choose the start of the onion address with `mkp224o`, it is compiled like this:
sudo apt-get install autoconf libsodium-dev git clone https://github.com/cathugger/mkp224o cd mkp224o/ ./autogen.sh ./configure make
Run the following command to get onion addresses starting with `name`:
./mkp224o -d ./keys name name2cv7s2t2cv4qbzem6bwjeub7gnifincy4lallp4fuk3whjiybgad.onion name2hz7z5oaksecttowa3ewb4w3hxaosfz5uxknjf7jzidfwxe3xtid.onion name33dio3amksrfqjowotnmdmosbqt4fs5jagxplsky3k5quez4vaqd.onion ^C
Choose an onion address, copy it the service configuration directory and restart tor:
cp keys/name2cv7s2t2cv4qbzem6bwjeub7gnifincy4lallp4fuk3whjiybgad.onion/* ~/tor/my_website/ # Restart tor tor -f ~/.torrc
Add an onion service to `.torrc`:
HiddenServiceDir /home/USER/tor/my_ssh HiddenServicePort 22 127.0.0.1:22
Install `torsocks` and start the ssh client like this:
sudo apt-get install torsocks torsocks ssh name2hz7z5oaksecttowa3ewb4w3hxaosfz5uxknjf7jzidfwxe3xtid.onion
On the server, install `tor` and the nntp server `inn2`:
apt-get install tor inn2
apt issues an error for `inn2` because `inn.conf` is invalid (on debian bullseye and more recent) and needs to be changed.
Configure inn2:
vi /etc/news/inn.conf organization: example-organization pathhost: news.example.com domain: example.com htmlstatus: false # limit article size maxartsize: 16384
Create a group:
ctlinnd newgroup tor.forum
Enable world access, add the lines below between `auth localhost` and `access localhost`:
vi /etc/news/readers.conf auth "world" { hosts: "*" default: "<world>" } access "world" { users: "<world>" newsgroups: "tor.forum" access: RPA }
Restart inn2:
/etc/init.d/inn2 restart
In the
Setting up a newsgroup server article
, I configured TLS and with tor it is unnecessary, the server uses port 119.
Configure the onion service in `.torrc`, add these lines:
HiddenServiceDir /home/USER/tor/my_newsgroup HiddenServicePort 119 127.0.0.1:119
Create the service directory and restart tor:
mkdir -p /home/USER/tor/my_newsgroup chmod 700 /home/USER/tor/my_newsgroup # Restart tor tor -f ~/.torrc
On the client, install `slrn` newsgroup client:
apt-get install slrn
Configure slrn, `ADDRESS_IN_HOSTNAME.onion` is the string in `/home/USER/tor/my_newsgroup/hostname`:
zcat /usr/share/doc/slrn/examples/slrn.rc.gz > ~/.slrnrc vi ~/.slrnrc server "ADDRESS_IN_HOSTNAME.onion" ".jnewsrc-tor"
Execute srln to connect, first time:
torsocks slrn -f ~/.jnewsrc-tor --create -h ADDRESS_IN_HOSTNAME.onion # press s to subscribe to the tor.forum newsgroup # then torsocks slrn -h ADDRESS_IN_HOSTNAME.onion
Add an onion service to `.torrc`:
HiddenServiceDir /home/USER/tor/my_simple HiddenServicePort 5000 127.0.0.1:5000
My server code is:
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <string.h> #include <stdlib.h> #include <unistd.h> int main(int ac, char **av){ int sock; struct sockaddr_in server; int mysock; char buf[1024]; int rval; sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0){ perror("Failed to create socket"); } server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons(5000); if (bind(sock, (struct sockaddr *) &server, sizeof(server))){ perror("bind failed"); exit(1); } listen(sock, 5); do { mysock = accept(sock, (struct sockaddr *)0, 0); if (mysock == -1) perror("accept failed"); else { memset(buf, 0, sizeof(buf)); if ((rval = recv(mysock, buf, sizeof(buf), 0)) < 0) perror("reading message"); else if (rval == 0) printf("Ending connection\n"); else printf("MSG: %s\n", buf); printf("Got the message (rval = %d)\n", rval); write(mysock, "OK", sizeof("OK")); close(mysock); } } while(1); }
Compile with:
gcc -g3 server.c -o server
The client has to connect to tor socks5 proxy, the socks5 protocol is described in the
My client code is:
#! /usr/bin/env sheepy #include "libsheepyObject.h" #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <netinet/in.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #define socks5Server "127.0.0.1" int main(int ac, char **av){ int sock; struct sockaddr_in server; struct hostent *hp; int mysock; char buf[1024*1024]; int rval; server.sin_family = AF_INET; if (!av[1]) { puts("address missing."); XFAILURE; } // connect to tor socks5 proxy 127.0.0.1:9050 hp = gethostbyname(socks5Server); if (hp==0) { perror("gethostbyname failed"); close(sock); exit(1); } memcpy(&server.sin_addr, hp->h_addr, hp->h_length); server.sin_port = htons(9050); stopwatchStart; sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0){ perror("Failed to create socket"); } if (connect(sock,(struct sockaddr *) &server, sizeof(server))){ perror("connect failed"); close(sock); exit(1); } // Socks5 RFC gemini://gmi.noulin.net/rfc/rfc1928.gmi // Authentication method negotiation // NO AUTHENTICATION REQUIRED buf[0] = 5; // version buf[1] = 1; // 1 byte method field buf[2] = 0; // no authentication required if(send(sock, buf, 3, 0) < 0){ perror("send failed"); close(sock); exit(1); } // response // version 5 // method 0 // accepted rval = recv(sock, buf, 2, 0); stopwatchLogUs; loghex(buf,2); put; // request buf[0] = 5; // version buf[1] = 1; // command: connect buf[2] = 0; // 0 buf[3] = 3; // address type: domain if (lenG(av[1]) > 255) { logE("address is too long"); ret 1; } buf[4] = lenG(av[1]); memcpy(buf + 5, av[1], buf[4]); buf[5+buf[4]] = 0x13; // port in network order 5000 buf[5+buf[4]+1] = 0x88; // port in network order 5000 logD("len %d", buf[4]); logD("addr: %s", buf + 5); loghex(buf, 5+buf[4]+2); put; if(send(sock, buf, 5+buf[4]+2, 0) < 0){ perror("send failed"); close(sock); exit(1); } rval = recv(sock, buf, 10, 0); stopwatchLogUs; // response must be // 0x5 // 0x0 >> succeeded loghex(buf, 10); put; if(send(sock,"WERWER", sizeof("WERWER"), 0) < 0){ perror("send failed"); close(sock); exit(1); } stopwatchLogUs; rval = recv(sock, buf, 10, 0); stopwatchLogUs; // response from server: OK puts(buf); printf("Sent: WERWER"); close(sock); }
Run the client with the onion address as argument:
./client.c address.onion
TOR/socks5 times:
Install an IRC server:
sudo apt-get install ngircd
Add an onion service configuration to .torrc:
HiddenServiceDir /home/USER/tor/my_irc HiddenServicePort 6667 127.0.0.1:6667
Restart tor:
tor -f ~/.torrc
The irc client I use is `tinyirc`, with the `torsocks` command it can connect to the irc onion service:
torsocks tinyirc nick name4ttgny3n5y72n2crrmf53d4a6ujubtgagn5cdm56yae3jzc4vkyd.onion
I tried torsocks with irssi and weechat but couldn't connect the irc onion service, I could connect regular irc service with a tor exit node.
Then I added support for socks5 proxys directly in tinyirc:
sudo apt-get install libncurses5-dev git clone https://github.com/nlaredo/tinyirc
Then apply the patch `0001-add-socks5-client-code.patch` (keep the tabs otherwise it wont apply) to commit 83ee1dae701de8c968044248fb9e2a6257dd5b74 (latest):
From 3dcbc2defb47a13ff14a0b7319ef4349f15fd45f Mon Sep 17 00:00:00 2001 From: Your Name <you@example.com> Date: Mon, 12 Dec 2022 19:36:14 +0100 Subject: [PATCH] add socks5 client code tinyirc.c | 105 +++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 77 insertions(+), 28 deletions(-) --- tinyirc.c | 105 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 77 insertions(+), 28 deletions(-) diff --git a/tinyirc.c b/tinyirc.c index cfe8998..a2d5974 100644 --- a/tinyirc.c +++ b/tinyirc.c @@ -880,37 +880,86 @@ char *hostname; { struct sockaddr_in sa; struct hostent *hp; - int s, t; - if ((hp = gethostbyname(hostname)) == NULL) + int s; + #define socks5Server "127.0.0.1" + if ((hp = gethostbyname(socks5Server)) == NULL) return -1; - for (t = 0, s = -1; s < 0 && hp->h_addr_list[t] != NULL; t++) { - bzero(&sa, sizeof(sa)); - bcopy(hp->h_addr_list[t], (char *) &sa.sin_addr, hp->h_length); + memcpy(&sa.sin_addr, hp->h_addr, hp->h_length); sa.sin_family = hp->h_addrtype; - sa.sin_port = htons((unsigned short) IRCPORT); - s = socket(hp->h_addrtype, SOCK_STREAM, 0); - if (s > 0) { - if (connect(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) { - close(s); - s = -1; - } else { - fcntl(s, F_SETFL, O_NDELAY); - my_tcp = s; - sprintf(lineout, "USER %s * * :%s\n", IRCLOGIN, IRCGECOS); - sendline(); - sprintf(lineout, "NICK :%s\n", IRCNAME); - sendline(); + sa.sin_port = htons(9050); + s = socket(hp->h_addrtype, SOCK_STREAM, 0); + if (s < 0){ + perror("Failed to create socket"); + return -1; + } + if (connect(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) { + perror("connect failed"); + close(s); + return -1; + } + char buf[1024] = {0}; + // Socks5 RFC gemini://gmi.noulin.net/rfc/rfc1928.gmi + // Authentication method negotiation + // NO AUTHENTICATION REQUIRED + buf[0] = 5; // version + buf[1] = 1; // 1 byte method field + buf[2] = 0; // no authentication required + if(send(s, buf, 3, 0) < 0){ + perror("send failed"); + close(s); + return -1; + } + // response + // version 5 + // method 0 + // accepted + int rval = recv(s, buf, 2, 0); + if (rval != 2 || buf[0]!= 5 || buf[1] != 0) { + puts("Socks5 authentication method negotiation failed"); + close(s); + return -1; + } + // request + buf[0] = 5; // version + buf[1] = 1; // command: connect + buf[2] = 0; // reserved 0 + buf[3] = 3; // address type: domain + if (strlen(hostname) > 255) { + puts("address is too long"); + return -1; + } + buf[4] = strlen(hostname); + memcpy(buf + 5, hostname, buf[4]); + uint16_t *port = (uint16_t*)&buf[5+buf[4]]; + *port = htons((unsigned short) IRCPORT); + if(send(s, buf, 5+buf[4]+2, 0) < 0){ + perror("send failed"); + close(s); + return -1; + } + rval = recv(s, buf, 10, 0); + if (rval < 2 || buf[0]!= 5 || buf[1] != 0) { + puts("Failed to connect to server"); + close(s); + return -1; + } + // response must be + // 0x5 + // 0x0 >> succeeded + fcntl(s, F_SETFL, O_NDELAY); + my_tcp = s; + sprintf(lineout, "USER %s * * :%s\n", IRCLOGIN, IRCGECOS); + sendline(); + sprintf(lineout, "NICK :%s\n", IRCNAME); + sendline(); #ifdef AUTOJOIN - sprintf(lineout, AUTOJOIN); - sendline(); + sprintf(lineout, AUTOJOIN); + sendline(); #endif - for (obj = olist; obj != NULL; obj = olist->next) { - sprintf(lineout, "JOIN %s\n", OBJ); - sendline(); - } /* error checking will be done later */ - } - } - } + for (obj = olist; obj != NULL; obj = olist->next) { + sprintf(lineout, "JOIN %s\n", OBJ); + sendline(); + } /* error checking will be done later */ return s; } int main(argc, argv) @@ -918,7 +967,7 @@ int argc; char **argv; { struct utmp ut, *utmp; - char hostname[64]; + char hostname[1024]; int i = 0; printf("%s Copyright (C) 1991-1996 Nathan Laredo\n\ This is free software with ABSOLUTELY NO WARRANTY.\n\ -- 2.30.2
Build `tinyirc`:
make
Connect to server with these commands:
export IRCNICK=myircnickname ./tinyirc name4ttgny3n5y72n2crrmf53d4a6ujubtgagn5cdm56yae3jzc4vkyd.onion
For gemini over tor experiment, I used the `gmnisrv` gemini server and the `amfora` gemini client.
Install `gmnisvr` as described in the my article
Building telescope gmni and gmnisvr
.
Add a service in .torrc:
HiddenServiceDir /home/USER/tor/my_gem HiddenServicePort 1965 127.0.0.1:1965
Amfora has a commit in which socks5 support is added:
Support SOCKS5 proxying @makeworld-the-better-one makeworld-the-better-one committed Dec 30, 2021 e3e1fc2
But there is no release with this commit:
So I compile `amfora` from source (install go, then compile amfora):
# Download latest version on https://golang.org/dl/ wget https://go.dev/dl/go1.19.4.linux-amd64.tar.gz tar xvf go1.19.4.linux-amd64.tar.gz sudo chown -R root:root ./go sudo mv go /usr/local export GOPATH=$HOME/work export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin git clone https://github.com/makeworld-the-better-one/amfora cd amfora make sudo make install export AMFORA_SOCKS5=127.0.0.1:9050 amfora gemini://address.onion
In `gmnisrv`, I get the error:
127.0.0.1 SSL accept error: error:14201076:SSL routines:tls_choose_sigalg:no suitable signature algorithm
Hashtag: #tor