Записать вывод awk в несколько переменных bash

Или как раскидать результат работы awk по нескольким переменным.

Преамбула

Предположим, у нас есть некоторая таблица в виде файла CSV с набором полей, например таких Login,FullName,Phone,Room,WorkTime и разделителем полей , (запятая):

verb666,Misha Verbitsky,+415314499922,42,11:00-16:00
ktvs421,Vasiliy Kotov,+415314499966,77a,00:00-06:00
dkldn89,Dmitry Kaledin,+415314499949,65b,22:00-00:00
vfurry1,Veniamin Furman,+415314499900,99,12:20-19:25
tpunk56,Tolik Punkoff,+415314499911,59,00:00-11:00

Нужно вытащить из нее некоторые данные, и далее как-либо обработать. Вытащить данные можно с помощью awk, используя оператор print, но возникает вопрос, как передать данные обратно в bash.

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

awk и eval

В bash есть встроенная команда eval, преобразующая переданную ей строку в команду или набор команд оболочки, и запускающая ее на выполнение. Этим и воспользуемся.

1. Организуем цикл, в котором будем производить обработку данных:

IFS_=$IFS
IFS=$'\n'
for TMPSTRING in $(cat "demotable.txt")
do
#тут будет код
done
IFS=$IFS_

Перед циклом я подправил переменную $IFS содержащую глобальные разделители, в нее, в частности, «смотрят» операторы циклов, чтобы определить, где начинается следующий элемент. По умолчанию переменная $IFS содержит пробел, табуляцию и перевод строки, но поскольку у нас есть данные с пробелом, то это не подходит, цикл будет работать неверно. Потому сохраняем старое значение во временную переменную, устанавливаем новое значение в перевод строки (\n). После цикла возвращаем значение на место.
В цикле организуем разбор данных:

echo "$TMPSTRING"|awk -F "," '{print "LOGIN=" $1; print "FULLNAME=" $2
print "PHONE=" $3; print "ROOM=" $4; print "WORKTIME=" $5 }'

Если запустить скрипт сейчас, то он выведет следующее:

LOGIN=verb666
FULLNAME=Misha Verbitsky
PHONE=+415314499922
ROOM=42
WORKTIME=11:00-16:00

Т.е. уже похоже на присваивание значений переменным bash, но есть проблема. Если мы сейчас скормим вывод awk eval‘у, то получим ошибку, например такую:

./awk2vars01: line 8: Verbitsky: command not found

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

awk print и вывод кавычки

Кавычки для оператора print awk являются служебными символами, в кавычки берутся строковые литералы, т.е. те строки, которые нужно вывести без изменений, как например, "LOGIN=" в коде выше. Экранирование (\") в операторе print тоже приведет к ошибке.

Первый вариант решения — завести внутреннюю переменную awk, содержащую кавычку, и печатать ее в нужном месте:

echo "$TMPSTRING"|awk -F "," '{print "LOGIN=" dq $1 dq; 
    print "FULLNAME=" dq $2 dq; print "PHONE=" dq $3 dq; print"ROOM=" dq $4 dq;
    print "WORKTIME=" dq $5 dq}' dq='"'

Второй вариант, отказаться от awk print и воспользоваться awk printf:

echo "$TMPSTRING"|awk -F "," '{printf "LOGIN=\"%s\"\n" \
	"FULLNAME=\"%s\"\n" \
	"PHONE=\"%s\"\n" \
	"ROOM=\"%s\"\n" \
	"WORKTIME=\"%s\"\n", 
	$1, $2, $3, $4, $5}'

Плюсы: все можно решить в одном операторе, и не нужно вводить дополнительные переменные.
Минусы: получается длинный и неудобный литерал (первый параметр awk printf) с описанием вывода, в котором легко запутаться. А переносить его на следующую строку еще неудобнее — надо брать строку в кавычки, а потом ставить пробел и \

Вывод при обеих вариантах получится аналогичный:

LOGIN="verb666"
FULLNAME="Misha Verbitsky"
PHONE="+415314499922"
ROOM="42"

Теперь можно обернуть все это в eval, чтобы раскидать результат работы awk по переменным.
Для кода с awk print:

eval $(echo "$TMPSTRING"|awk -F "," '{print "LOGIN=" dq $1 dq; 
    print "FULLNAME=" dq $2 dq; print "PHONE=" dq $3 dq; print"ROOM=" dq $4 dq;
    print "WORKTIME=" dq $5 dq}' dq='"')

Для кода с awk printf:

eval $(echo "$TMPSTRING"|awk -F "," '{printf "LOGIN=\"%s\"\n" \
	"FULLNAME=\"%s\"\n" \
	"PHONE=\"%s\"\n" \
	"ROOM=\"%s\"\n" \
	"WORKTIME=\"%s\"\n", 
	$1, $2, $3, $4, $5}')

В демо-скрипте я просто вывожу данные на консоль, в реальном скрипте, что понятно, можно делать обработку данных в переменных bash.

echo "Login: $LOGIN"
echo "Full name: $FULLNAME"
echo "Phone: $PHONE"
echo "Room: $ROOM"
echo "Work time: $WORKTIME"

Вывод (и для одного варианта кода, и для другого):

Login: verb666
Full name: Misha Verbitsky
Phone: +415314499922
Room: 42
Work time: 11:00-16:00

...

Скрипты полностью можно посмотреть на GitHub

Немного об оптимизации

Получение строки с определенным номером из файла в Linux

С помощью sed

sed -n 5p /path/to/file

Получить 5 строку из текстового файла с путем /path/to/file

С помощью awk

awk 'NR == 5' /path/to/file

На мой взгляд sed‘ом несколько проще, потому что не нужны лишние движения для подстановки переменных shell/bash-скрипта:

TEXTFILE="/etc/group"
STRNO=5

TMPSTRING=`sed -n "$STRNO"p "$TEXTFILE"`

Dialog — псевдографический оконный интерфейс в bash-скриптах

Оказывается, в bash-скриптах можно организовать псевдографический оконный интерфейс с помощью команды dialog. Не буду тут подробно про нее расписывать, потом покажу ее использование на реальном проекте, а пока заметка от склероза.

Краткий мануал на английском

Копия в PDF

Примеры скриптов на GitHub

Скачать в архиве

Установка и настройка I2P в Slackware Linux

Преамбула

I2P это такая скрытая пиринговая сеть, подробнее можно узнать в Википедии или на официальном сайте. В отличии от TOR, она обеспечивает не анонимный доступ в Интернет, а доступ к собственным ресурсам (сайтам, файлообменникам и т.д.), скрытым из обычной сети. Гейты в «большой» Интернет в ней есть, но они кривые, косые и пользоваться ими не рекомендуется. Расскажу, как ее установить и настроить на Slackware, заодно разрешив пользователям из локальной сети также получать к ней доступ.

Установка Java

Клиент сети написан на Java, потому ее надо сначала установить. На официальном сайте есть рекомендации о необходимой версии:
Java Runtime Version 7 or higher. (Oracle, OpenJDK, or IcedTea Java Version 7 or 8 recommended.
Сама установка довольно проста:
1. Идем, например сюда
2. Скачиваем jdk-8u162-i586-2gds.txz
3. Устанавливаем стандартным образом:

installpkg jdk-8u162-i586-2gds.txz

4. Добавляем в автозагрузку (если вы не сделали отдельного скрипта для запуска сервера, то /etc/rc.d/rc.local) пути к java:

echo "Add JAVA paths..."
export JAVA_HOME=/usr/lib/java
export MANPATH="${MANPATH}:${JAVA_HOME}/man"
export PATH="${PATH}:${JAVA_HOME}/bin:${JAVA_HOME}/jre/bin"

5. Перезагружаем машину.
6. Вводим в консоли команду java без параметров. Если все было сделано правильно, то вы должны увидеть вывод краткой справки по параметрам java.

Создание пользователя для I2P

Понятно, что операции с пользователями надо делать под root или с sudo.

1. Создаем отдельную группу для I2P:

groupadd i2pgrp

2. Создаем интерактивного (пока, потом мы вырубим ему всю интерактивность) пользователя, например i2psrv:

useradd -g i2pgrp -m -d /home/i2psrv -s /bin/bash i2psrv

где:
-g i2pgrp — группа пользователя (i2pgrp)
-m — создать домашний каталог
-d /home/i2psrv — путь к домашнему каталогу (/home/i2psrv)
-s /bin/bash — установить пользователю оболочку, в данном случае фиктивную (/bin/bash)
i2psrv — имя пользователя

3. Задаем ему пароль:

passwd i2psrv

В интерактивном режиме повторяем пароль 2 раза, о сложности можно не беспокоиться — все равно потом отключим.

Установка

1. Скачиваем установщик для Linux с официального сайта
2. Копируем в директорию пользователя (/home/i2psrv) и меняем владельца файла:

chown i2psrv:i2pgrp i2pinstall_0.9.44.jar

3. Логинимся под новым пользователем.
4. Запускаем установку (через консоль):

java -jar i2pinstall_0.9.44.jar -console

5. Приводят возможность выбрать язык:

Select your language
0 [x] eng
1 [ ] bra
2 [ ] cat
3 [ ] ces
...

Оставляем английский (нажимая ENTER).

6. Далее предлагают продолжить установку:
Нажимаем 1 [ENTER]

7. Опять лицензия и всякая хрень:
Нажимаем 1 [ENTER]

8. Выбор пути для установки. Поскольку устанавливаем в каталоге нового пользователя, пусть так и делает — нажимаем [ENTER]

9. Далее нажимаем O и [ENTER] (в прошлых версиях было меньше гемора и подтверждений, а сейчас словно анкету в ментовку работать заполняешь 🙂

10. Еще раз предлагают подтвердить, что все ОК (1 и [ENTER])
11. Наконец, тебе говорят, что все ОК:

====================
Installation started
Framework: 5.1.3-84aaf (IzPack)
Platform: linux,version=4.4.14-smp,arch=x86,symbolicName=null,javaVersion=1.8.0_232
[ Starting to unpack ]
[ Processing package: Base (1/1) ]
[ Unpacking finished ]
Installation finished
On most systems, I2P can be started with:

/home/i2psrv/i2p/i2prouter start

If I2P does not start, please try:

/home/i2psrv/i2p/runplain.sh

12. Тебе говорят, что все совсем ОК:

Installation was successful
Application installed on /home/i2psrv/i2p
[ Writing the uninstaller data ... ]
[ Console installation done ]

Расшаривание I2P-сервисов в локальной сети.

Если вы намерены использовать I2P только на локальном компьютере, этот шаг можно пропустить.

1. Идем в файл /home/i2psrv/i2p/i2ptunnel.config, предварительно его куда-нибудь скопировав, и меняем в нем все 127.0.0.1 на адрес нашего компьютера в локальной сети (например на 192.168.0.20, см. адрес вашего компьютера), таким образом все сервисы I2P будут доступны с любой машины в локальной сети.
2. В том же файле смотрим порты, если где-то у нас какой-то порт для чего-то занят, например на том же порту уже висит HTTP или TOR-proxy, смело меняем порт.

Переключение пользователя

I2P — порядочный сервис, и сам умеет переключать пользователя, под которым запускается. Некоторые даже рекомендуют завести двух пользователей, одного для запуска, другого для установки I2P, но мы, ради экономии времени, делать этого не будем — и запуск и установка будут под одним пользователем. Тем не менее, необходимо отредактировать скрипт i2prouter/home/ip2srv/i2p):

1. Ищем строку, содержащую RUN_AS_USER=
2. Раскомментируем ее (удаляем # в начале строки).
3. Дописываем после знака = имя пользователя (в этом примере «i2psrv").

Расшаривание Web-консоли

Отслеживание статуса соединения с сетью I2P, ошибки и основные настройки доступны через Web-интерфейс, который запускается на локальной машине на порту 7657, но если физического доступа к той машине, на которой установлен I2P нет (или лень), то можно управлять ей и с любого компьютера локальной сети.

Внимание! Это не очень одобряется официальными инструкциями. По идее можно сделать безопасный SSL-туннель, как это описывалось в одной из старых инструкций. Но я опишу самый простой вариант, просто поменяю конфиг.

Заходим в clients.config (/home/i2psrv/i2p), предварительно сделав бэкап.
И опять меняем 127.0.0.1 на 192.168.0.20, т.е. меняем адрес машины, по которому должна появиться консоль.
Далее меняем clientApp.4.startOnLoad=true на clientApp.4.startOnLoad=false, т.к. на сервере нет смысла открывать панель управления после старта I2P.

Дальнейшая настройка под катом

Проверка

Переходим по адресу http://i2p-projekt.i2p

I2P довольно медленная сеть и работает с некоторыми перебоями, так что если вместо сайта вы увидите надпись «Сайт недоступен. Возможно, сайт отключен, сеть перегружена или ваш маршрутизатор недостаточно интегрирован с другими пирами. Вы можете повторить операцию.«, то действительно, скорее всего, операцию нужно повторить.

Отключаем интерактив пользователю i2psrv

На самом деле интерактивный доступ к системе для пользователя i2psrv был нужен только на этапе установки сервиса I2P, и я оставлял его до конца настройки на случай, если I2P понадобится переустановить. Теперь консоль пользователю i2psrv более не нужна. Отключаем:

Редактируем (под root‘ом) файл /etc/passwd.
Находим в этом файле строку, начинающуюся с имени пользователя (i2psrv) и в конце строки меняем /bin/bash на /bin/false.
Сохраняем файл.

Что дальше?

Остались нераскрытыми темы подписок (как добавлять I2P-сайты неизвестные вашему маршрутизатору I2P), интересные I2P-сайты, другие сервисы I2P, кроме WWW. Может быть когда-нибудь вернусь к этому вопросу, а пока рекомендую детально ознакомиться с документацией на сайте https://geti2p.net/, http://i2p-projekt.i2p и в консоли I2P.

Настройка времени через консоль Linux

Делается с помощью команды

date --set "<строка>"

Например:

date --set "Dec 12 5:08:00 2019"

Сохранение:

hwclock -w

Эту команду надо выполнить после установки времени командой date.

Просмотр времени и даты — команда date без параметров.

Пример вывода:

Wed Dec 18 16:53:28 AKST 2019

Источник, копия статьи в PDF, там еще есть и другие способы настройки.

Установка и настройка tor-ноды

Установка tor

1. Загружаем исходники tor отсюда я взял версию 0.4.2.4-rc посвежее.

2. Собираем пакет:
— Распаковываем из архива каталог tor-0.4.2.4-rc со всеми подкаталогами
— Переходим в этот каталог и выполняем последовательно:

./configure
make
checkinstall

checkinstall нас спросит, какой пакет хотим создать (Slackware [S], RPM [R] or Debian [D]?), отвечаем s, далее вводим описание пакета, например tor и нажимаем два раза ENTER, после чего подтверждаем, что все верно (нажав ENTER еще раз) и checkinstall создаст пакет.

3. Можно сразу его установить:

installpkg tor-0.4.2.4-rc-i386-1.tgz

Создаем пользователя для tor

Негоже запускать tor под обычным пользователем, а тем более под root‘ом, потому создадим для него отдельного пользователя. Пользователь будет неинтерактивный, т.е. войти в систему с терминала он не сможет.

1. Добавляем группу, например torgroup:

groupadd torgroup

2. Смотрим файл /etc/shells и проверяем, чтоб в файле была строка /bin/false, если ее нет — смело дописываем.

3. Создаем пользователя с именем, например, torusr:

useradd -g torgroup -m -d /home/torusr -s /bin/false torusr

где:
-g torgroup — группа пользователя (torgroup)
-m — создать домашний каталог
-d /home/torusr — путь к домашнему каталогу (/home/torusr)
-s /bin/false — установить пользователю оболочку, в данном случае фиктивную (/bin/false)
torusr — имя пользователя

4. Создаем каталог для данных tor:

cd /home/torusr
mkdir .tordata

и изменяем владельца созданного каталога на torusr

chown torusr:torgroup .tordata

Настройка tor-ноды

В каталоге /home/torusr создаем файл torrc и записываем в него следующие строки:

SocksPort 9050 — порт на localhost, где будет висеть tor, и принимать на него запросы. Проще говоря, это порт прокси-сервера, который надо будет прописать, чтоб соединиться с сетью tor с локальной машины. Порт 9050 является портом по умолчанию, и назначается на localhost (127.0.0.1), если строки SocksPort будут отсутствовать в конфигурации.

SocksPort 192.168.0.20:9660 — то же самое, только внутри локальной сети. Клиенты из локальной сети должны будут подключаться по адресу 192.168.0.20 и порту 9666, чтобы использовать сеть tor.

Tor организует только SOCKS5 прокси, как быть с браузерами, которым нужен HTTP, рассмотрим далее.

SocksPolicy accept 192.168.0.0/24
SocksPolicy accept 127.0.0.1
SocksPolicy reject *

Принимать запросы только из локальной сети и localhost’а.

Log notice file /home/torusr/notices.log — файл, куда будет писаться лог tor’а

RunAsDaemon 1 — запуск tor в режиме демона.

DataDirectory /home/torusr/.tordata — путь для данных tor

ORPort 9001 — порт, используемый для пересылки пакетов с других узлов.

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

Конечно, стоило бы облегчить жизнь пользователям, сидящим за сетевыми экранами и пустить трафик по портам 80 (8080) или 443, но я пока не стал. Впрочем, если вам будет надо — смотрите статью на Хабре (копия)

RelayBandwidthRate 1000 MB
RelayBandwidthBurst 2000 MB
— ограничение пропускной способности. Чем больше, тем лучше. Но настраивайте эти числа под свой канал, чтоб не загадить его трафиком tor совсем.

Nickname PersonalChaosRelay — имя вашего релея (ноды) в базе tor. Можете придумать любое, но советую сначала проверить придуманное имя здесь, введя его в поиске. Если ничего не найдется, проздрабляю, ваш релей будет уникальным.

ExitPolicy reject *:*
ExitPolicy reject6 *:*
— запрет использовать tor-ноду в качестве выходной. Для ГОРФ параметр строго обязательный.
Примечание: в /usr/local/etc/tor находится файл torrc.sample с подробным описанием конфигурации.
Пример файла конфигурации на PasteBin

Устанавливаем файлу правильного владельца:

chown torusr:torgroup torrc

Запуск ноды

Запуск осуществляется следующей командой:

sudo -u torusr tor -f /home/torusr/torrc

Если помещать запуск в автозагрузку, то желательно указать полный путь к файлу tor:

sudo -u torusr /usr/local/bin/tor -f /home/torusr/torrc

Запуск в отдельном network namespace (копия):

ip netns exec provns sudo -u torusr /usr/local/bin/tor -f /home/torusr/torrc

provns — имя network namespace

Проверка работоспособности

Минут через 15-20 после запуска можно заглянуть в /home/torusr/notices.log, если в последних строках файла написано что-то типа:

Self-testing indicates your ORPort is reachable from the outside. Excellent. Publishing server descriptor.
Tor has successfully opened a circuit. Looks like client functionality is working.
Self-testing indicates your DirPort is reachable from the outside. Excellent.
Performing bandwidth self-test...done.

значит порты ORPort и DirPort доступны извне, и нода нормально функционирует.

Если же в логе что-то типа:

Your server (x.x.x.x:9001) has not managed to confirm that its ORPort is reachable. Relays do not publish descriptors until their ORPort and DirPort are reachable. Please check your firewalls, ports, address, /etc/hosts file, etc.
Your server (x.x.x.x:9030) has not managed to confirm that its DirPort is reachable. Relays do not publish descriptors until their ORPort and DirPort are reachable. Please check your firewalls, ports, address, /etc/hosts file, etc.

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

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

Настройка для клиентов под катом

Network namespaces или несколько виртуальных сетевых карт (интерфейсов) с разными IP на одной машине.

С одной физической сетевой картой.

Для чего.

Например мы хотим организовать следующую схему:
1. После запуска сервер устанавливает соединение с VPN-провайдером, и весь трафик идет через VPN.
2. Некоторым программам VPN не нужен, пусть это например будут TOR, I2P (у них и так шифрование, плюс им бы желательно скорость работы повыше, а напрямую соединяться быстрее, чем через VPN). Плюс, например, мы хотим ходить на некоторые сайты в обход VPN, либо иметь возможность запускать в обход VPN какие-либо трафикоемкие программы, например торрент-клиент. Ну пусть еще будет отдельный локальный сервис, например FTP, также висящий на отдельном IP.

Как.

В Linux есть замечательный механизм network namespaces, который на одной машине позволяет создать несколько изолированных друг от друга сетевых подсистем, почти как сеть в виртуальной машине. Не бойтесь, все делается на уровне ядра, потому тормозов, характерных для виртуальных машин не будет. И пусть слово «изолированных» вас тоже не пугает, когда надо — изолированных, а когда надо — мы их свяжем.

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

Подготовка

Поскольку в процессе нам придется поднимать/опускать физические и виртуальные сетевые карты, настоятельно советую отключить Network Manager, а основную сеть настроить вручную. С включенным Network Manager может ничего не получиться, т.к. он в самый ответственный момент влезет и напоганит в конфигурации.

Как на Slackware отключить Network Manager и настроить сеть вручную (копия)

Создание и конфигурация network namespace.

Конфигурация namespace’ов производится с помощью iproute2.

1. Создаем новый неймспейс с именем provns:

ip netns add provns

2. Создаем две связанных между собой виртуальных сетевых карты (интерфейса)

ip link add veth0 type veth peer name veth1

3. Поднимаем интерфейс veth0:

ifconfig veth0 0.0.0.0 up

4. Ассоциируем вторую виртуальную карту с созданным нэймспейсом:

ip link set veth1 netns provns

Получился один дополнительный namespace, связанный с основным виртуальными сетевыми интерфейсами veth0 и veth1.

Теперь надо связать виртуальный интерфейс veth0 с физической сетевой картой (интерфейсом) eth0. Сделать это можно разными способами, например, присвоить интерфейсам разные IP-адреса из разных подсетей и сделать маскарадинг с помощью IPTABLES, а можно воспользоваться мостами.

Мост — специальное сетевое устройство (в данном случае не физическое, а логическое) позволяющее связать два (и более) сетевых интерфейса на канальном уровне, как в маршрутизаторе.

Подробнее про мосты:
Linux Bridge
Виртуальные сетевые устройства в Linux: Linux Bridge
10 примеров команды brctl в Linux для сетевого Ethernet моста
Эти статьи в PDF

Итак:
5. Отключаем физический интерфейс eth0:

ifconfig eth0 down

6. Включаем его, но IP-адрес не присваиваем (IP-адрес будет присвоен мосту):

ifconfig eth0 0.0.0.0 up

7. Создаем мост br0:

brctl addbr br0

8. Соединяем (добавляем интерфейсы к мосту) eth0 и veth0:

brctl addif br0 eth0 veth0

9. Поднимаем (включаем) мост, присваивая ему IP-адрес и маску подсети:

ifconfig br0 192.168.0.15 netmask 255.255.255.0 up

Получилось как на схеме:

10. Устанавливаем маршрут по умолчанию в основном namespace:

ip route add default via 192.168.0.1 dev br0 src 192.168.0.15

Далее конфигурируем namespace:

Выполнение любых команд в указанном namespace производится командой

ip netns exec <имя_namespace> <команда> [параметры_команды]

Например, если мы хотим выполнить ifconfig в namespace с именем provns, то команда будет:

ip netns exec provns ifconfig

11. Поднимаем (включаем) сетевой интерфейс veth1 внутри нэймспейса provns, и присваиваем ему адрес 192.168.0.20:

ip netns exec provns ifconfig veth1 192.168.0.20 netmask 255.255.255.0

12. Прописываем внутри нэймспейса маршрут по умолчанию:

ip netns exec provns ip route add default via 192.168.0.1 dev veth1 src 192.168.0.20

13. Поднимаем внутри namespace’а loopback-интерфейс:

ip netns exec provns ifconfig lo 127.0.0.1

Скрипт для автоматизации настройки network namespace.

Под катом

Скрипт целиком на GitHub

Настройка сети в Slackware Linux вручную.

Краткая заметка, как настроить сеть на Slackware вручную. Все делаем под root’ом или через sudo.

1. Отключаем Network Manager, если случайно включили его при установке системы.

Для этого идем в /etc/rc.d и снимаем права на выполнение у файла rc.networkmanager

chmod -x rc.networkmanager

2. Проверяем, что у скрипта rc.inet1 установлены права на исполнение.

3. Правим rc.inet1.conf:

— Раскомментируем строчки для нужного сетевого (ых) интерфейса (ов) и прописываем нужные данные. У меня только один интерфейс (сетевая карта) eth0, поэтому я раскомментировал строчки в начале конфигурационного файла и прописал нужные данные:

# Config information for eth0:
IPADDR[0]="192.168.0.15"
NETMASK[0]="255.255.255.0"
USE_DHCP[0]=""
DHCP_HOSTNAME[0]=""

IPADDR — адрес компьютера в локальной сети.
NETMASK — маска подсети

DHCP использовать не будем, настроим DNS вручную далее, поэтому USE_DHCP и DHCP_HOSTNAME оставляем, как было.

— Настраиваем основной шлюз. Ищем в rc.inet1.conf строчку GATEWAY и прописываем основной шлюз (обычно адрес роутера, в некоторых деревенско-колхозных случаях адрес шлюза надо спрашивать у провайдера):

GATEWAY="192.168.0.1"

4. Указываем адреса DNS-серверов.
В файл /etc/resolv.conf добавляем адреса DNS-серверов. Тут я указал публичные гуглевские DNS:

nameserver 8.8.8.8
nameserver 8.8.4.4

5. Перезагружаем систему.

Проверить можно в той же консоли, сделав ping до того же гуглевского DNS:

ping 8.8.8.8

И попробовать посетить какой-нибудь сайт:
lynx tolik-punkoff.com

Пример конфига GRUB для загрузки сервера

# GRUB configuration file '/boot/grub/menu.lst'.
# generated by 'grubconfig'.

# Start GRUB global section
timeout 10
color light-gray/blue black/light-gray
# End GRUB global section

# Linux bootable partition
  title Slackware 14.2
  root (hd0,1)
  kernel /abs/vmlinuz root=/dev/mapper/sda1 ro video=VGA-1:640x480@75
  initrd /abs/initrx.gz
# Linux bootable partition ends

# Linux bootable partition test initrd
  title Slackware Test/Rescue initrd
  root (hd0,1)
  kernel /abs/vmlinuz root=/dev/sda1 ro video=VGA-1:640x480@75
  initrd /abs/initrd.gz
# Linux bootable partition nocryprt ends

# Puppy Slacko bootable partition config begins
  title Slacko Puppy Linux
  root (hd0,1)
  kernel /slacko/vmlinuz ro vga=normal
  initrd /slacko/initrd.gz
# Puppy Slacko bootable partition config ends

На Pasebin

Внимание! Названия устройств и путей могут не совпадать с описанными в мануале! Будьте внимательны и поправьте под свою конфигурацию!

Установка Linux и шифрование ее и всего содержимого жесткого диска. Часть IV

Этап #19
Восстановление системы на зашифрованный диск. Форматирование разделов

Сначала, как и на этапе 18, необходимо получить доступ к зашифрованному жесткому диску
tcplay --map=cryp_sdb --device=/dev/sdb --keyfile=/path/to/key/file

Далее, с помощью утилиты kpartx, доступ к разделам на жестком диске
kpartx -av /dev/mapper/cryp_sdb

где:
Опция a – подключить разделы, содержащиеся на зашифрованном устройстве
Опция v – отобразить, какие разделы были подключены.
/dev/mapper/cryp_sdb – подключенный с помощью tcplay зашифрованный диск.

Далее форматируем разделы. Главный:
mkfs –t ext2 /dev/mapper/cryp_sdb1
Дополнительный:
mkfs –t ext2 /dev/mapper/cryp_sdb5
И раздел подкачки:
mkswap /dev/mapper/cryp_sdb6

Отключаем подключенные разделы:
kpartx –dv /dev/mapper/cryp_sdb

Отключаем зашифрованный жесткий диск:
tcplay --unmap=cryp_sdb
Перезагружаемся обратно в консоль тестового initrd

Этап #20
Восстановление системы на зашифрованный диск. Восстановление файлов из ранее созданных бэкапов.

Как и в предыдущем этапе, сначала получаем доступ к зашифрованному жесткому диску:
tcplay --map=cryp_sdb --device=/dev/sdb --keyfile=/path/to/key/file

И его разделам:
kpartx -av /dev/mapper/cryp_sdb

Предположим, что бэкапы системы были сохранены на первый FAT32 раздел флешки sda1 и находятся по следующим путям:
/mnt/sdb1/bak/system.tar.gz и /mnt/sdb1/bak/home.tar.gz

Создаем точку монтирования для флешки (если не создана):
mkdir /mnt/sdb1
И монтируем ее (если не примонтирована)
mount –t vfat /dev/sdb1 /mnt/sdb1

Создаем точки монтирования для разделов жесткого диска:
mkdir /mnt/sda1
mkdir /mnt/sda5

Внимание! Точки монтирования для жестких дисков должны называться также, как назывались при создании бэкапов!

Монтируем разделы:
mount –t ext2 /dev/mapper/cryp_sdb1 /mnt/sda1
mount –t ext2 /dev/mapper/cryp_sdb5 /mnt/sda5

Распаковываем архивы:

tar –xvf /mnt/sda1/bak/home.tar.gz –C /
tar –xvf /mnt/sda1/bak/system.tar.gz –C /

где:
Опция x – распаковать архив
Опция v – отображать имена распаковываемых файлов
Опция f – архив находится в файле (а не направлен со STDIN)
/mnt/sda1/bak/home.tar.gz – путь к файлу архива
–C – указывает, в какой каталог распаковать архив (сам каталог указывается через пробел, и в данном случае это корень, т.е. / ).

Скопируем заранее исправленные fstab и mtab, предположим, они были сохранены в первый раздел загрузочной флешки, в каталог tabs и данный раздел смонтирован:

cp /mnt/sdb1/tabs/fstab /mnt/sda1/etc/fstab
cp /mnt/sdb1/tabs/fstab /mnt/sda1/etc/mtab

После копирования файлов отмонтируем разделы:
umount /mnt/sda1
umount /mnt/sda5

Отключаем подключенные разделы:
kpartx –dv /dev/mapper/cryp_sdb

Отключаем зашифрованный жесткий диск:
tcplay --unmap=cryp_sdb
Перезагружаемся уже с рабочим initrd.

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

Скачать мануал целиком в PDF

Установка Linux и шифрование ее и всего содержимого жесткого диска. Часть III

Этап #16
Подготовка конфигурационных файлов и рабочего initrd

На этом этапе первым делом определимся, под каким именем мы будем обращаться к нашему зашифрованному жесткому диску. Это имя будет использоваться в команде map утилиты tcplay. Для примера здесь и далее я буду использовать имя cryp_sdb.
Далее необходимо скопировать в отдельный каталог на загрузочной флешке (для примера пусть будет cfg) файлы /etc/fstab и /etc/mtab из основной ОС и отредактировать их, заменив /dev/sdaX на /dev/mapper/cryp_sdbX. Где X – номер конкретного раздела на жестком диске.
Далее под катом

Установка Linux и шифрование ее и всего содержимого жесткого диска. Часть II

Этап #11.
Добавление tcplay в образ initrd.

Для этого создаем какой-нибудь временный каталог и распаковываем туда из пакета (tc-play-2.0-i486-1.tgz в моем случае) полученного на этапе 8 файлы (дальнейшие пути внутри пакета)
usr/lib/libtcplay.so.2.0
usr/sbin/tcplay
Я просто воспользовался mc, зашел им в архив и нужное скопировал клавишей F5 в /tmp/tc-play, mc сам вызвал архиватор и распаковал все за меня.
Далее, выходим из архива и копируем во временный каталог (ну чтоб все нужные файлы были в одном месте и мы не запутались) файл
/lib/libdevmapper.so.1.02 (если при создании initrd, вы пользовались опцией –L, то эта библиотека уже на месте)
Теперь из временного каталога (да, можно было и сразу) скопируем файлы
libtcplay.so.2.0
libdevmapper.so.1.02
в /boot/initrd-tree/lib
(каталог библиотек файловой системы initrd)
а файл
tcplay
в /boot/initrd-tree/bin

Также tcplay во время своей работы, а конкретно подключения зашифрованных разделов вызывает из каталога /usr/sbin программу dmsetup. Соответственно, необходимо положить dmsetup в /boot/initrd-tree/usr/sbin

Чтобы dmsetup работал правильно, ему необходим каталог /dev/mapper, его тоже надо создать
mkdir /boot/initrd-tree/dev/mapper

Далее выходим из каталога initrd-tree, удаляем из директории /boot ранее созданный initrd.gz и запускаем mkinitrd без параметров, далее примонтируем нашу загрузочную флешку, заменяем файл /mnt/sda2/absolute/initrd.gz на пересозданный initrd.gz, перезагружаем компьютер и выбираем созданный на этапе 8 пункт для тестирования initrd.gz

Если все сделано правильно, то в конце загрузки будет выведено сообщение «Hello, world!» и приглашение оболочки, в котором мы введем команду tcplay. Программа должна выдать краткую справку по своим параметрам. После чего вводим команду exit и загружаемся в основную ОС.

Этап #12.
Генерация ключа для шифрования.

Для генерации ключа можно взять данные из /dev/urandom.
Если было несколько перезагрузок основной ОС и ОС некоторое время работала, то это должно быть довольно надежно. Хотя при написании данной статьи я и сомневался в этом, но мои сомнения были развеяны более опытными специалистами 🙂
Можно также воспользоваться генератором ключевых файлов, входящим в комплект Windows или Linux-версии Truecrypt, в таком случае следует использовать версию 7.1a, последнюю на момент закрытия проекта Truecrypt, скачать каковую можно, например отсюда.

Можно воспользоваться сторонними генераторами случайных высокоэнтропийных последовательностей, а можно взять (как и при использовании Truecrypt) любой файл, первый мегабайт которого и будет использован в качестве ключевого файла.
Нежелательно в последнем случае использовать в качестве такого файла какой-нибудь стандартный системный файл или фотографию вашего кота, понятно, что при получении доступа к жесткому диску, злоумышленник сможет его без особого геморроя подобрать.

Вот команда для генерации ключа с помощью /dev/random – стандартного устройства для получения псевдослучайных последовательностей
dd if=/dev/random of=/путь/к/файлу/имя_файла bs=1 count=256

Команда dd подробно описана, например, здесь

Далее под катом

Установка Linux и шифрование ее и всего содержимого жесткого диска.

Нам понадобятся:
1. Дистрибьютив Linux. Я здесь и далее использовал Slackware 14.2
2. Live CD Linux, я использовал Puppy Rus Slacko,

Идея в том, чтоб наша ОС и данные находились на надежно зашифрованных разделах, на жестком диске внешне не должно быть никакой разбивки, а система загружалась без ввода парольной фразы или ключа.
Как это можно реализовать
Загрузчик системы и ключ доступа будут храниться на небольшом(<50Mb) разделе флешки, при включении загрузчик разблокирует доступ к шифрованному винту, загружает ядро, далее происходит обычная загрузка системы.

Я не стал использовать LVM, а вместо LUKS выбрал клон truecrypt’а — tcplay

Этап #1. Разбиение диска на разделы

Итак, первым делом создаем нужные разделы на диске. Я сделал это в графической оболочке Puppy Rus с помощью имеющегося на диске gparted, но ничего не мешает вам сделать это с помощью другой программы.

Этап #2.
Подготовка загрузочной флешки.

Действуем как в вышеупомянутой статье – разбиваем флешку на 2 раздела, первый большой и видимый из Windows и других ОС, второй маленький – с загрузчиком операционной системы и ключами, отформатированный в Ext2. В статье рекомендуется сделать его приблизительно 50 Мб, и для загрузчика GRUB, ядра, хранения начальных настроек этого хватит. Я же сделал второй раздел побольше (1Гб) и перенес на него дополнительно Live дистрибутив Puppy Linux (чтоб в процессе настроек не грузиться с CD или другой флэшки).

Этап #3.
Установка загрузчика GRUB

Необходимо извлечь загрузочные флешки с которых ставили ОС, и/или с которых загружали Puppy Slacko, если таковые были использованы, и вставить нашу размеченную подготовленную загрузочную флешку.

Я воспользовался графической утилитой установки GRUB c LiveCD Puppy Slacko, доступ к которой можно получить из главного меню Puppy Slacko (оно по-умолчанию там же где и «Пуск» у Windows) «Система» — «Настройка загрузчика GRUB»
1. В первом диалоговом окне выбираем способ установки simple
2. Во втором предлагается выбрать разрешение экрана при загрузке, я выбрал standart, ибо для Slackware потом все равно необходимо перенастроить параметры разрешения экрана при загрузке в конфиге GRUB.
3. В следующем окне необходимо указать местоположение директории boot, это второй раздел нашей флешки, который у меня называется sdb2, соответственно указывается устройство /dev/sdb2
4. В следующем окне выбираем запись загрузчика в MBR
5. В следующем окне вводим устройство, в MBR которого будет записан загрузчик, в данном случае это наша флешка, которая обозначена как /dev/sdb (у меня)

Продолжение под катом

Поздравляю! Мы загрузились с помощью образа initrd до загрузки основной ОС.
Для продолжения загрузки надо ввести exit и нажать enter. Управление будет передано программе init из основной ОС и основная ОС загрузится.

Домашний сервер на базе Slackware Linux

Давно хотел собрать в кучу заметки про то, как можно организовать домашний сервер (или сервер для малого офиса) на базе Slackware Linux с VPN, I2P, Tor, файл-помойкой на локальном FTP, возможностью установки с сервера ПО и операционных систем, а возможно и с внутренними Web-сайтами, чатами и что там еще надо в зависимости от ваших задач. А еще и с полным шифрованием жесткого(-их) дисков.

Это пост-оглавление. Тут буду копить внутренние ссылки на заметки, относящиеся к организации сервера. Нумерация и последовательность также может меняться, т.к. я пишу как придется, а в содержании буду по мере накопления материала сортировать как надо.

Что примерно надо построить на начальном этапе. Сервер в локальной сети, позволяющий клиентам выходить в Интернет, как минимум через два различных IP (VPN и IP основного провайдера), поддерживающий локальный FTP и/или Samba (файловое хранилище), поддерживающий проходную ноду Tor и I2P-роутер, а также обеспечивающий локальным клиентам доcтуп в сети Tor и I2P.

Ремарка про железо. На самом деле, чем круче, тем круче, но изначально все делалось на старом Celeron с 500 Гб HDD и 512 Мб ОП, сейчас все вертится на Dual Core Intel Celeron E3200 (2400МГц) с гигабайтом встроенной памяти и встроенным видео, тоже не самая новая машина, но получше. А вообще хочу, чтоб оно на PIII-700 заработало. Сетевая карта одна (расскажу, как из одной реальной виртуальных наделать).

Оглавление

Установка Linux и шифрование жесткого диска:
Часть I Копия
Часть II Копия
Часть III Копия
Часть IV Копия
Пример конфига GRUB для загрузки сервера Копия
Эта часть целиком в PDF

Начальная настройка сети Копия
Network namespaces или несколько виртуальных сетевых карт (интерфейсов) с разными IP на одной машине. Копия
Настройка файерволла (IPTABLES) Копия

Локальный FTP Копия
Нода TOR Копия
Настройка доступа к I2P Копия
PXE (установка и запуск различных ОС со своего сервера на локальных машинах) Копия

Локальный прокси-сервер:
Запускающий скрипт Копия
Инструкция по установке Копия
Изменения в конфигурации последней версии Копия

Настройка IPTables на сервере. Часть вторая, с поправками.

Итак, раньше копия мы уже делали первоначальную настройку IPTables, но оказалось, что делали не очень верно.

Товарищ [info]wasserstrahl@ljr внес поправку:

Открытие порта на исходящие соединения.

Ну чтоб с чем-то связаться по определенному порту.

iptables -A INPUT -p tcp —sport <# порта> -j ACCEPT
iptables -A OUTPUT -p tcp —dport <# порта> -j ACCEPT»

Нет.

iptables -A OUTPUT -p tcp —dport <# порта> -j ACCEPT» — это верно вроде,

а «iptables -A INPUT -p tcp —sport <# порта> -j ACCEPT» — нет. Потому что это правило позволяет любой входящий пакет с указанного порта с любого адреса. Если ты хочешь открыть ответы на исходящий трафик, то нужно писать что-то в стиле iptables -A INPUT -p tcp -m state —state RELATED,ESTABLISHED -j ACCEPT

Поправка верная, потому изменяем настройку IPTables в скрипте инициализации сервера.

Удаляем все правила файерволла:

# Delete all rules
echo "Delete firewall rules..."
iptables -F
iptables -F -t nat
iptables -F -t mangle
iptables -X
iptables -t nat -X
iptables -t mangle -X

Устанавливаем основную политику по умолчанию. Запретить все соединения (параноидальный режим):

# Drop all traffic
echo "Set main policy..."
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP

Разрешаем принимать все установленные входящие соединения. Это надо для того, что если мы откроем порт на исходящие соединения, для того, чтоб сервер мог с чем-то связываться (например с WWW или rsync), то ответ был бы принят.

#prinimat' vse ustanovlennye vhodashie soedineniya
echo "Accepts all established inbound connections..."
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

Открываем порт для клиентов, которые подключаются к серверу по протоколу PPTP (входящий трафик):

#open VPN ports and GRE
echo "Open VPN ports and GRE..."
#to computer
iptables -A INPUT -p tcp --dport 1723 -j ACCEPT
iptables -A OUTPUT -p tcp --sport 1723 -j ACCEPT

И разрешаем для них же протокол GRE:

iptables -A INPUT -p gre -j ACCEPT
iptables -A OUTPUT -p gre -j ACCEPT

Поскольку сам сервер не будет соединяться с VPN-провайдером по протоколу PPTP (есть OpenVPN), то следующие строки я убрал:

iptables -A INPUT -p tcp --sport 1723 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 1723 -j ACCEPT

Разрешаем весь трафик на loopback (lo) интерфейсе. Если у нас будут сервисы, такие как Web-сервер и сервер баз данных MySQL на одном сервере, то связываться они будут как раз через lo-интерфейс.

#accept all traffic an lo interface
echo "Accept all lo interface traffic..."
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

Открываем на вход 22 порт (ssh) для клиентов, которые подключатся к серверу через PPTP VPN:

# ssh (22 port)
echo "Open 22 port (ssh) for VPN clients..."
iptables -A INPUT -s 172.16.1.0/24 -p tcp --dport 22 -j ACCEPT
iptables -A OUTPUT -s 172.16.1.0/24 -p tcp --sport 22 -j ACCEPT

Так же разрешаем им доступ к удаленному рабочему столу (XDMCP):

# XDMCP
echo "Open 177 port UDP (XDMCP) for VPN clients..."
iptables -A INPUT -s 172.16.1.0/24 -p udp --dport 177 -j ACCEPT
iptables -A OUTPUT -s 172.16.1.0/24 -p udp --sport 177 -j ACCEPT

echo "Open 6000:6005 ports (Windows XDMCP) in both directions for VPN clients..."
iptables -A INPUT -s 172.16.1.0/24 -p tcp -m multiport --dports 6000:6005 -j ACCEPT
iptables -A OUTPUT -s 172.16.1.0/24 -p tcp -m multiport --sports 6000:6005 -j ACCEPT

iptables -A INPUT -s 172.16.1.0/24 -p tcp -m multiport --sports 6000:6005 -j ACCEPT
iptables -A OUTPUT -s 172.16.1.0/24 -p tcp -m multiport --dports 6000:6005 -j ACCEPT

Разрешаем VPN-клиентам доступ к DNS:

echo "Open DNS for VPN clients..."
iptables -A INPUT -s 172.16.1.0/24 -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -s 172.16.1.0/24 -p udp --sport 53 -j ACCEPT

iptables -A INPUT -s 172.16.1.0/24 -p tcp --dport 53 -j ACCEPT
iptables -A OUTPUT -s 172.16.1.0/24 -p tcp --sport 53 -j ACCEPT

Разрешаем протокол ICMP (ping):

# Allow ICMP
echo "Allow ICMP and ports for TRACEROUTE..."
iptables -A INPUT -p icmp -j ACCEPT
iptables -A OUTPUT -p icmp -j ACCEPT

И исходящие порты для TRACEROUTE (ответы, входящий трафик уже разрешен командой iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT):

#open ports from traceroute
iptables -A OUTPUT -p udp -m multiport --dports 33434:33534 -j ACCEPT

Открываем стандартные порты (HTTP, HTTPS, email, rsync) для доступа к соответствующим сервисам с сервера (входящие):

#Open standart ports (from computer)
echo "Open standart ports (DNS,WWW, email) from server"
# 53-DNS,80 8080/tcp - WWW, 443/tcp - https, 110,443,25,587 - e-mail 873/tcp - rsync (for sbopkg)
iptables -A OUTPUT -p udp -m multiport --dports 53,443 -j ACCEPT
iptables -A OUTPUT -p tcp -m multiport --dports 53,80,8080,443,110,443,25,587,873 -j ACCEPT

Запускаем PPTP VPN сервер (к его настройке вернусь несколько позже):

#start VPN server
echo "Starting PPTD VPN server..."
pptpd &

Производим окончательную настройку файервола для PPTP VPN клиентов:
1. Организуем NAT (маскарадинг):

echo "Final firewall settings for VPN clients..."
#NAT for VPN clients
iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -j MASQUERADE

И немного подправляем пакеты (без этого виснут некоторые соединения). Буду благодарен, если мне кто-нибудь объяснит почему, но кстати, в Ростелекомовском файерволе такая настройка не установлена, потому это плохой провайдер, и их VPN висючий. В свое время задолбался с этим глюком.

#popravlaem pakety (bez etogo visnut nekotorye soedinenia)
iptables -A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

Скрипт целиком на PasteBin

Источники к сожалению пролюбил.

tinyproxy свалился после обновления

Черт меня дернул обновить tinyproxy, о настройке которого я писал здесь копия

Свалился вот с такой ошибкой:

"Bind" cannot be used with transparent support enabled.
Syntax error on line 37
Unable to parse config file. Not starting.
Not starting (code 70)

Хотя никакое прозрачное проксирование я не включал.

Решилось тем, что строку 37:

Bind <адрес_сервера>

я просто закомментировал. После этого он штатно заработал.

Правда, нифига понять не могу, с чего это вдруг он так странно упал. В прошлой версии все работало, и вроде команда Bind правильная, нужная и на месте.

Настройка IPTABLES

На самом деле, жутко не люблю настраивать IPTables, поскольку синтаксис у него несколько инопланетный. Дома и на работе я как-то настроил один раз лет 10 назад и благополучно все забыл. Теперь вот приходится мучительно вспоминать: «Чем ты это делал? Ну вот этой вот мясорубкой.».

Настройки обновлены, старые под катом

Вроде все правильно, но стойкое ощущение, что где-то накосячил. Кто больше шарит в IPTABLES, приму все комментарии по поводу данной темы.