-- Leo's gemini proxy

-- Connecting to gmi.noulin.net:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini

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


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:


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:


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

-- Response ended

-- Page fetched on Wed May 22 02:22:33 2024