💾 Archived View for gmi.noulin.net › 2022-12-23-using-tor.gmi captured on 2023-06-14 at 14:17:48. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-01-29)

-=-=-=-=-=-=-

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:

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.

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-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

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:

./client.c address.onion

TOR/socks5 times:

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:

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

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:

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