Using Tor
Feed
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
tor project page
, 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:
- Web server onion service
- SSH onion service
- My own tcp server onion service
- IRC onion service
- Gemini failed experiment
Onion services are within the tor network and don't need tor exit nodes.
To create onion service, you need:
- to install `tor`
- configure the onion service in the .torrc file
- setup the service
After starting tor, it takes less than 30 seconds for the onion service to become accessible.
To create a regular internet service, you need:
- to buy a domain
- setup the dns for your server ip
- setup letsencrypt to get a tls certificate
- setup the service
- setup the service to use the tls certificate and restart when needed
From my experience, the tor network is quite slow, it's like using the internet with a 56kbauds modem.
How to create a simple http onion service
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
How to create an SSH onion service
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
How to create a newsgroups onion service
On the server, install `tor` and the nntp server `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:
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:
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
Creating my own client and server
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
SOCKS5 RFC 1928
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:
TOR/socks5 times:
- socks5 authentication: 1.8ms
- connect to server: 2 sec
- send/receive in ms
How to create an irc onion service and connect to it
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:
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`:
Connect to server with these commands:
export IRCNICK=myircnickname
./tinyirc name4ttgny3n5y72n2crrmf53d4a6ujubtgagn5cdm56yae3jzc4vkyd.onion
Failed experiment: gemini client and server
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:
- Latest release v1.9.2 on Dec 10, 2021
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
Feed
Guestbook