Tinc

Небольшой демон, позволяющий строить Mesh сети в нескольких режимах, а именно Routing (когда маршрутизацией занимается tincd, switch - когда маршрутизация отдаётся на откуп OS, но производится mac learning и hub - когда трафик рассылается во все порты)

Установка

Весь tinc в Gentoo замаскирован, поэтому берём не самую свежую версию, чтобы можно было коннектиться с другими участниками сети спокойной и не искать почему теряются пакеты. В Debian stretch версия tinc - 1.0.31, так что остановимся на ней

# emerge -v =tinc-1.0.31

В общем-то здесь наверное и всё.

Настройка

В отличии от более современных версий tinc, в которых изначальна впилены возможности по bootstrap'у новых сетей, в предыдущих версиях такого функционала нет, поэтому придётся немного поработать руками. Олсо, rc-скрипт tinc для openrc не адаптирован, так что вместо привычного нам service.instance придётся править конфиг, куда прописывать запускаемые демоно сети.

Итак, структура каталогов тинка достаточно проста

/etc/
|- tinc/
 |- <network name>
  |- tinc.conf - конфиг демона
  |- tinc-up - скрипт, исполняемый после создания интерфейса
  |- tinc-down - скрипт, исполняемый перед удалением интерфейса
  |- rsa_key.priv - закрытая часть rsa ключа
  |- hosts/ - директория с "карточками" участников сети
   |- host1
   |- host2
   |- host3

Собственно для начала работы с tinc достаточно создать структуру каталогов, как представлено выше, написать в tinc.conf что-нибудь следующее:

tinc.conf
Name = host1
Device = /dev/net/tun
ConnectTo = host2
ConnectTo = host3
Port = 665

и сгенерировать связку ключей для текущего хоста:

# tincd -n <network name> -K

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

После чего повторить процедуру на всех хостах.

Карточка хоста выглядит примерно так:

host1
----RSA PUBLIC KEY BLOCK----
....
----END RSA PUBLIC KEY BLOCK----
Subnet = 10.0.0.1/32

Кстати интересный момент, даже если для сети выбрана размерность шире, в карточке хоста всё равно его непосредственный ip-адрес надо указывать с маской /32. А вот сети, которые находятся за хостом можно писать напрямую префиксами.

И ещё один немаловажный момент - tinc сам не вешает маршруты и адреса на свои интерфейсы, для этого служат скрипты tinc-up и tinc-down, причем они обязательно должны быть исполняемыми. Например вот такими:

tinc-up
#!/bin/bash
 
ip link set up $INTERFACE
ip a add 10.0.0.1/24 dev $INTERFACE
tinc-down
#!/bin/bash
 
ip a add 10.0.0.1/24 dev $INTERFACE
ip link set down $INTERFACE

Аналогично, но со своими адресами настраиваются и остальные хосты.

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

Так же у tinc есть возможность работать в режим switch'а. Для этого в конфиге нужно добавить одну строчку:

tinc.conf
...
Mode = switch
...

После этого данная нода начнёт обрабатывать пакеты стандартным l2 стэком. Единственное но, которое я заметил, это то, что в сети нельзя использовать разные ноды, т.е. либо всё в роутинге, либо всё в свитчинге.

Взаимодействие с tinc

Просмотр коннектов и прочего

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

Из важного, у каждого коннекта есть статус, который не очень очевиден:

typedef struct connection_status_t {
    unsigned int pinged: 1;         /* sent ping */
    unsigned int active: 1;         /* 1 if active.. */
    unsigned int connecting: 1;     /* 1 if we are waiting for a non-blocking connect() to finish */
    unsigned int unused_termreq: 1; /* the termination of this connection was requested */
    unsigned int remove: 1;         /* Set to 1 if you want this connection removed */
    unsigned int timeout: 1;        /* 1 if gotten timeout */
    unsigned int encryptout: 1;     /* 1 if we can encrypt outgoing traffic */
    unsigned int decryptin: 1;      /* 1 if we have to decrypt incoming traffic */
    unsigned int mst: 1;            /* 1 if this connection is part of a minimum spanning tree */
    unsigned int proxy_passed: 1;   /* 1 if we are connecting via a proxy and we have finished talking with it */
    unsigned int unused: 22;
} connection_status_t;

Собственно здесь реализована битовая маска. Из распространённых статусов:

  • 0018 (active, remove) - нет подключения к ноде
  • 001a (active, unused_termreq, remove) - есть связность с нодой (причём не важно, прямая или через метаноду)
  • 0020 (timeout) - хост недоступен