Найти тему
Tima_Barsov

Поднимаем сайт в tor

Многим людям, которые не очень хорошо разбираются в IT сфере, кажется, что создать и поднять свой собственный сайт в торе очень сложно и геморройно. Тем не менее, данная статья признана развеять этот миф и доказать, что даже человек, в первый раз установивший на флешку Linux уже способен сделать себе простой сайт, который будет нормально работать и функционировать.

Всё что нам потребуется - это компиляторы языков Си / Go, операционная система Linux (некоторые UNIX подобные также сойдут), программа make и пакет tor. При помощи всех этих средств мы можем начать стряпню.
Здесь будет расписан соответственно код, который поможет автоматизировать создание сайта и внесение изменений в конфигурационный файл тора. Этот код будет написан на языке Си.
На языке же программирования Go мы будем создавать непосредственно серверную программу.
Статья не является документацией такого рода, что я буду объяснять написанный мною код.
Здесь вы сами должны будете анализировать код и пытаться понимать что написано.
Если вы не знаете языки программирования, но хотите выучить хоть какой-то, то не теряйте времени и учитесь. Благо информации в интернете по многим языкам предостаточно.
Если вы уже знаете хотя бы основы выбранных мною языков, тогда добро пожаловать в мир, где вы будете сами анализировать код.
Если же вы в программировании NULL или не знаете выбранные мною языки, то не переживайте, я надеюсь, не будет сложной задачей выучить две комбинации клавиш Ctrl+C и Ctrl+V.
Ну и давайте начинать.
Первое, что нам нужно сделать - это подумать об архитектуре программы.
Я лично разбил программу, на пять составных частей:

||||||1. [ Подготовка | backgr.c ] Создание директорий и первоначальных файлов
2. [ Конфигурация | confgr.c ] Дополнение torrc и запуск сервисов tor'a
3. [ Результаты | result.c ] Получение hostname файла
4. [ Запуск | wakeup.c ] Поднятие сайта в сети tor
5. [ Связка | main.c ] Связка вышеперечисленных программ||||||

Помимо файлов расширения .c будут также и заголовочные файлы расширения .h:

|||1. [ Константы | macro.h ]
2. [ Типы данных | types.h ]
3. [ Связка функций | onion.h ]|||

Код этих заголовочных файлов крохотный, так что можем сразу его посмотреть:

File: macro.h

"80 "
#define IP_PORT "127.0.0.1:80"

#define HIDDEN_DIR "HiddenServiceDir "
#define HIDDEN_PORT "HiddenServicePort "

#define MAIN_DIR "www"

#define TORRC_DIR "/etc/tor/torrc"

#define CHOICE_DIR "onion"
#define PRIVATE_DIR "/var/lib/tor/onion/"

File: types.h

#pragma once

typedef enum {false, true} bool;

File: onion.h

extern void backgr(void);
extern void confgr(void);
extern void result(void);
extern void wakeup(void);

Последний файл, в нашей коллекции - это Makefile,

который просто содержит инструкции для компиляции файлов расширения .c:

File: Makefile

CC = gcc
FL = *.o *.i *.s main

.PHONY: default build clean

default: build

build: main.o backgr.o confgr.o result.o wakeup.o
$(CC) -save-temps main.o backgr.o confgr.o result.o wakeup.o -o main

clean:
rm -rf $(FL)

main.o: main.c
$(CC) -c main.c -o main.o
backgr.o: backgr.c
$(CC) -c backgr.c -o backgr.o
confgr.o: confgr.c
$(CC) -c confgr.c -o confgr.o
result.o: result.c
$(CC) -c result.c -o result.o
wakeup.o: wakeup.c
$(CC) -c wakeup.c -o wakeup.o

main.c:
$(error "main.c not found")
backgr.c:
$(error "backgr.c not found")
confgr.c:
$(error "confgr.c not found")
result.c:
$(error "result.c not found")
wakeup.c:
$(error "wakeup.c not found")

И теперь приступим непосредственно к нашим Си файлам.

Кода будет много, так что попытайтесь запастись чайком и печеньками:

Начнём по порядку с файла backgr.c.

Задачи этого файла следующие:

- Проверка наличия директорий

- Создание директорий при их отсутствии

- Проверка наличия файлов

- Создание файлов при их отсутствии:

  Генерация кода html и go файлов.

File: backgr.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>

#include "macro.h"
#include "types.h"

#define DEBUG

static bool dirIsExist(const char * const name) {
DIR *dir = opendir(name);
if (dir != NULL) {
closedir(dir);
#ifdef DEBUG
printf("[DIR '%s' IS EXIST]\n", name);
#endif
return true;
}
#ifdef DEBUG
printf("[DIR '%s' IS NOT EXIST]\n", name);
#endif
return false;
}

static bool fileIsExist(const char * const name) {
FILE *file = fopen(name, "r");
if (file != NULL) {
fclose(file);
#ifdef DEBUG
printf("[FILE '%s' IS EXIST]\n", name);
#endif
return true;
}
#ifdef DEBUG
printf("[FILE '%s' IS NOT EXIST]\n", name);
#endif
return false;
}

static void createDir(const char * const dir) {
char command[6 + MAX_LENGTH];
sprintf(command, "mkdir %s", dir);
system(command);
#ifdef DEBUG
printf("[DIR '%s' CREATED]\n", dir);
#endif
}

static bool createFile(const char * const name, const char * const content) {
FILE *file = fopen(name, "w");
if (file != NULL) {
fputs(content, file);
fclose(file);
#ifdef DEBUG
printf("[FILE '%s' CREATED]\n", name);
#endif
return true;
}
#ifdef DEBUG
printf("[FILE '%s' NOT CREATED]\n", name);
#endif
return false;
}

extern void backgr(void) {
chdir("/");

if (!dirIsExist(MAIN_DIR))
createDir(MAIN_DIR);

#ifdef DEBUG
printf("[CHDIR '%s']\n", MAIN_DIR);
#endif
chdir(MAIN_DIR);

if (!dirIsExist(CHOICE_DIR))
createDir(CHOICE_DIR);

if (!fileIsExist("main.go"))
createFile("main.go",
"package main\n"
"\n"
"import (\n"
" \"fmt\"\n"
" \"net/http\"\n"
")\n"
"\n"
"func index(w http.ResponseWriter, r *http.Request) {\n"
" http.ServeFile(w, r, \""CHOICE_DIR"/index.html\")\n"
"}\n"
"\n"
"func main() {\n"
" fmt.Println(\"Server is listening ...\")\n"
"\n"
" http.HandleFunc(\"/\", index)\n"
" http.ListenAndServe(\""IP_PORT"\", nil)\n"
"}\n"
);

#ifdef DEBUG
printf("[CHDIR '%s']\n", CHOICE_DIR);
#endif
chdir(CHOICE_DIR);

if (!fileIsExist("index.html"))
createFile("index.html",
"<!DOCTYPE html>\n"
"<html>\n"
"<head>\n"
" <title>[ CryATor-group ]</title>\n"
" <meta charset=\"utf-8\">\n"
"</head>\n"
"<body>\n"
" <h3>Generated by ZXONS</h3>\n"
" <p>hello, world</p>\n"
"</body>\n"
"</html>\n"
);
}

Файл confgr.c

Задачи:

- Проверка конфигурационного файла torrc на содержание следующих двух строк:

  HiddenServiceDir /var/lib/tor/onion/

  HiddenServicePort 80 127.0.0.1:80

- Запись этих строк в конфигурационный файл torrc при их отсутствии

- Запуск сервисов tor'a: systemctl start tor.service

- Перезапуск сервисов tor'a: systemctl restart tor.service

File: confgr.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include "macro.h"
#include "types.h"

#define DEBUG

static bool exist[2] = {false, false};

static bool hiddenServiceExist(const char * const hs[2]) {
FILE * const torrc = fopen(TORRC_DIR, "r");
char buffer[BUFF_SIZE / 2];

if (torrc != NULL) {
while (fgets(buffer, BUFF_SIZE, torrc) != NULL) {
if (strcmp(buffer, hs[0]) == 0) exist[0] = true;
else if (strcmp(buffer, hs[1]) == 0) exist[1] = true;

if (exist[0] && exist[1]) break;
}
fclose(torrc);
}

if (exist[0] && exist[1]) {
#ifdef DEBUG
printf("[DATA '%s' and '%s' FOUND]\n", HIDDEN_DIR, HIDDEN_PORT);
#endif
return true;
}

#ifdef DEBUG
printf("[DATA '%s' or '%s' NOT FOUND]\n", HIDDEN_DIR, HIDDEN_PORT);
#endif
return false;
}

static void appendHiddenService(const char * const hs[2]) {
FILE * const torrc = fopen(TORRC_DIR, "a");
if (torrc != NULL) {
if (!exist[0]) {
#ifdef DEBUG
printf("[DATA '%s' ADDED]\n", HIDDEN_DIR);
#endif
fputs(hs[0], torrc);
}
if (!exist[1]) {
#ifdef DEBUG
printf("[DATA '%s' ADDED]\n", HIDDEN_PORT);
#endif
fputs(hs[1], torrc);
}
fclose(torrc);
}
}

extern void confgr(void) {
const char * const hidden_service[2] = {
[0] = HIDDEN_DIR PRIVATE_DIR "\n",
[1] = HIDDEN_PORT PORT IP_PORT "\n"
};

if (!hiddenServiceExist(hidden_service))
appendHiddenService(hidden_service);

#ifdef DEBUG
printf( "[SYS 'systemctl start tor.service']\n"\
"[SYS 'systemctl restart tor.service']\n");
#endif

system("systemctl start tor.service");
system("systemctl restart tor.service");

sleep(1);
}

Файл result.c

Задача:

- Копирование файла hostname в директорию /www

File: result.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "macro.h"

#define DEBUG

extern void result(void) {
#ifdef DEBUG
printf("[CHDIR '%s']\n", "../");
#endif
chdir("../");

#ifdef DEBUG
printf("[COPY '%s' to '%s']\n", PRIVATE_DIR"hostname", ".");
#endif
system("cp "PRIVATE_DIR"hostname .");
}

Файл wakeup.c

Задачи:

- Компиляция файла языка Go

- Запуск скомпилированной программы

File: wakeup.c

#include <stdio.h>
#include <stdlib.h>

#define DEBUG

extern void wakeup(void) {
#ifdef DEBUG
printf("[SYS 'go build main.go']\n");
#endif
system("go build main.go");

#ifdef DEBUG
printf("[SYS './main']\n");
#endif
system("./main");
}

File: main.c

#include <stdio.h>
#include "onion.h"

int main(void) {
backgr();
confgr();
result();
wakeup();

return 0;
}

Все вышеперечисленные файлы должны находиться в одной директории.

Компиляция и запуск нашей программы будет выглядить следующим образом:

$ make build
$ sudo ./main

При компиляции будет следующий результат:

gcc -c main.c -o main.o
gcc -c backgr.c -o backgr.o
gcc -c confgr.c -o confgr.o
gcc -c result.c -o result.o
gcc -c wakeup.c -o wakeup.o
gcc -save-temps main.o backgr.o confgr.o result.o wakeup.o -o main

Программу необходимо запускать из под root пользователя, так как она работает с объектами вне директории обычного пользователя.

При первом запуске самой программы, мы увидем следующее:

[DIR 'www' IS NOT EXIST]
[DIR 'www' CREATED]
[CHDIR 'www']
[DIR 'onion' IS NOT EXIST]
[DIR 'onion' CREATED]
[FILE 'main.go' IS NOT EXIST]
[FILE 'main.go' CREATED]
[CHDIR 'onion']
[FILE 'index.html' IS NOT EXIST]
[FILE 'index.html' CREATED]
[DATA 'HiddenServiceDir ' or 'HiddenServicePort ' NOT FOUND]
[DATA 'HiddenServiceDir ' ADDED]
[DATA 'HiddenServicePort ' ADDED]
[SYS 'systemctl start tor.service']
[SYS 'systemctl restart tor.service']
[CHDIR '../']
[COPY '/var/lib/tor/onion/hostname' to '.']
[SYS 'go build main.go']
[SYS './main']
Server is listening ...

Теперь мы имеем фактически две директории:

1) /var/lib/tor/onion/ - директория, в которой расположены файлы hostname и private_key

Файл hostname содержит просто сгенерированное имя вашего .onion сайта.

Файл же private_key содержит приватный RSA ключ вашего сайта.

И данный файл необходимо хранить как зеницу ока, иначе если вы его потеряете, то и потеряете хостнейм.

2) /www/ - директория, в которой расположен сгенерированный Go файл, скомпилированный Go файл, также содержится hostname сайта и соответственно здесь находится директория onion (в нашем случае), в которой будут содержаться все ваши html/css/js файлы.

Если вы теперь попробуете перейти по хостнейму, допустим в тор-браузере, то у вас отобразится сгенерированный вами сайт, который вы уже впоследствии можете сами разукрашивать.

При повторном запуске программы, созданные файлы, а также другие данные подобия ключа и соответственно хостнейма перезаписываться не будут, таким образом, вы сможете использовать данный скомпилированный файл как запуск вашего сайта.

[DIR 'www' IS EXIST]
[CHDIR 'www']
[DIR 'onion' IS EXIST]
[FILE 'main.go' IS EXIST]
[CHDIR 'onion']
[FILE 'index.html' IS EXIST]
[DATA 'HiddenServiceDir ' and 'HiddenServicePort ' FOUND]
[SYS 'systemctl start tor.service']
[SYS 'systemctl restart tor.service']
[CHDIR '../']
[COPY '/var/lib/tor/onion/hostname' to '.']
[SYS 'go build main.go']
[SYS './main']
Server is listening ...